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
@@ -1,2634 +0,0 @@
1
- /*! (c) gotoAndPlay | All rights reserved */
2
- (window["webpackJsonpapplication"] = window["webpackJsonpapplication"] || []).push([["module-12~module-13~module-9"],{
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 happenso, 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
- default:
549
- classNames = 'col-sm-auto';
550
-
551
- }
552
-
553
- // Generate boilerplate html, surrounding the actual widget (label, numeric stepper, etc)
554
- this.innerHTML = `
555
- <div class="form-group position-relative row">
556
- <div class="col-sm-5 col-lg-4 col-form-label form-label-container">
557
- <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>
558
- </div>
559
- <div class="inner-widget align-self-center ${classNames}">
560
- <span class="k-invalid-msg" data-for="${this._data.name}"></span>
561
- </div>
562
- </div>
563
- `;
564
- }
565
- else
566
- {
567
- this.innerHTML = `
568
- <div class="form-group position-relative">
569
- <div class="col-form-label form-label-container">
570
- <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>
571
- </div>
572
- <div class="inner-widget">
573
- <span class="k-invalid-msg" data-for="${this._data.name}"></span>
574
- </div>
575
- </div>
576
- `;
577
- }
578
-
579
- // Create inner widget (must be overridden)
580
- let widget = this._generateInnerWidget();
581
-
582
- // Append inner widget
583
- $(this).find('.inner-widget').prepend(widget);
584
- }
585
-
586
- /**
587
- * TO BE OVERRIDDEN
588
- */
589
- _generateInnerWidget()
590
- {
591
- // Show an error, should be overridden
592
- console.error(`Unable to create ${this._data.type} form item for configuration parameter ${this.id}`);
593
- }
594
-
595
- /**
596
- * Set attributes on the widget configuration object.
597
- */
598
- _setWidgetAttributes(config)
599
- {
600
- const attribs = this._data.attributes;
601
-
602
- if (attribs)
603
- {
604
- for (let attr in attribs)
605
- {
606
- config[attr] = attribs[attr];
607
-
608
- if (attr == 'pattern')
609
- config['data-pattern-msg'] = 'Contains invalid characters';
610
- }
611
- }
612
- }
613
-
614
- /**
615
- * Set additional attributes on the widget configuration object to properly validate input.
616
- */
617
- _setWidgetValidationAttributes(config)
618
- {
619
- const val = this._data.validator;
620
-
621
- if (val != null && val != '')
622
- {
623
- if (val == 'ip')
624
- {
625
- 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]?)$';
626
- config['data-pattern-msg'] = 'Invalid IP address';
627
- config['required'] = true;
628
- config['data-required-msg'] = 'Required';
629
- }
630
-
631
- else if (val == 'notNull')
632
- {
633
- config['required'] = true;
634
- config['data-required-msg'] = 'Required';
635
- }
636
-
637
- else if (val == 'pwd')
638
- {
639
- config['pattern'] = '^.{6,}$';
640
- config['data-pattern-msg'] = 'Minimum length: 6 characters';
641
- }
642
-
643
- else if (val == 'posNum')
644
- {
645
- config['pattern'] = '^[0-9]\d*$';
646
- config['data-pattern-msg'] = 'Non-negative number required';
647
- }
648
-
649
- else if (val == 'aoi')
650
- {
651
- // Nothing to do
652
- // See Kendo validation initialization in config-interface-builder.js
653
- }
654
-
655
- else if (val == 'url')
656
- {
657
- config['type'] = 'url';
658
- config['data-url-msg'] = 'Invalid URL';
659
- }
660
- }
661
- }
662
-
663
- /**
664
- * Initialize form item.
665
- *
666
- * NOTE: must be overridden if inner widget requires special initialization (for example Kendo widgets)
667
- */
668
- _initialize()
669
- {
670
- // Set value
671
- this._setWidgetValue();
672
-
673
- // Set edit enabled
674
- this._setWidgetEditEnabled();
675
- }
676
-
677
- /**
678
- * TO BE OVERRIDDEN
679
- */
680
- _setWidgetValue()
681
- {
682
- // Nothing to do, must be overridden
683
- }
684
-
685
- /**
686
- * TO BE OVERRIDDEN
687
- */
688
- _setWidgetEditEnabled()
689
- {
690
- // Nothing to do, must be overridden
691
- }
692
-
693
- /**
694
- * TO BE OVERRIDDEN
695
- */
696
- _onValueInput(e)
697
- {
698
- // Nothing to do, must be overridden
699
- }
700
-
701
- _triggerEvent()
702
- {
703
- if (this._data.trigger)
704
- {
705
- let event = new CustomEvent('value-set', {detail: null, bubbles: true, cancelable: true});
706
- this.dispatchEvent(event);
707
- }
708
- }
709
- }
710
-
711
- // DEFINE COMPONENT
712
- if (!window.customElements.get('config-form-item'))
713
- window.customElements.define('config-form-item', ConfigFormItem);
714
-
715
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
716
-
717
- /***/ }),
718
-
719
- /***/ "./src/components/uibuilder/config-grid.js":
720
- /*!*************************************************!*\
721
- !*** ./src/components/uibuilder/config-grid.js ***!
722
- \*************************************************/
723
- /*! exports provided: ConfigGrid */
724
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
725
-
726
- "use strict";
727
- __webpack_require__.r(__webpack_exports__);
728
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigGrid", function() { return ConfigGrid; });
729
- /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
730
- /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
731
- /* 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");
732
-
733
-
734
-
735
-
736
- class ConfigGrid extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
737
- {
738
- constructor(configParam, editEnabled, inDialog)
739
- {
740
- super(configParam, editEnabled, inDialog);
741
- }
742
-
743
- /**
744
- * Create widget to render the ConfigParameter.
745
- * @override
746
- */
747
- _generateInnerWidget()
748
- {
749
- // Create main widget's html
750
- this._widgetHtml = $('<div>', {class: ''});
751
-
752
- // Set grid widget configuration
753
- let gridConfig = {
754
- id: this._data.name,
755
- name: this._data.name,
756
- class: 'limited-height' + (!this._data.editable ? ' no-interact' : '')
757
- };
758
-
759
- // Append grid to main html; grid will be converted to Kendo widget during initialization
760
- this._widgetHtml.append($('<div>', gridConfig));
761
-
762
- if (this._data.editable)
763
- {
764
- // BUTTONS
765
-
766
- // Create buttons container
767
- let buttons = $('<div>', {class: 'mt-2 text-right'});
768
-
769
- // Append buttons to container
770
- this._addButton = $('<button>', {type: 'button', class: 'k-button k-secondary', title: 'Add'}).append($('<i class="fas fa-plus"></i>'));
771
- this._editButton = $('<button>', {type: 'button', class: 'k-button k-secondary ml-2', title: 'Edit', disabled: true}).append($('<i class="fas fa-pen"></i>'));
772
- this._removeButton = $('<button>', {type: 'button', class: 'k-button k-secondary ml-2', title: 'Remove', disabled: true}).append($('<i class="fas fa-times"></i>'));
773
-
774
- buttons.append(this._addButton);
775
- buttons.append(this._editButton);
776
- buttons.append(this._removeButton);
777
-
778
- // Append buttons container to main html
779
- this._widgetHtml.append(buttons);
780
-
781
- // Create edit dialog
782
- // NOTE: data-dismiss="modal" on the close/cancel buttons was removed to work around an issue with nested modals;
783
- // the custom "data-cancel" attribute is used to add a custom listener to the buttons
784
- this._editDialog = $(`
785
- <div class="modal" tabindex="-1" role="dialog" aria-labelledby="modalTitle" aria-hidden="true" data-keyboard="false" data-backdrop="static">
786
- <div class="modal-dialog modal-dialog-centered" role="document">
787
- <div class="modal-content">
788
- <div class="modal-header">
789
- <h5 class="modal-title text-primary" id="modalTitle">${this._data.label}</h5>
790
- <button type="button" class="close" aria-label="Close" data-cancel="modal">
791
- <span aria-hidden="true">&times;</span>
792
- </button>
793
- </div>
794
- <div class="modal-body in-flow-invalid-msg">
795
-
796
- </div>
797
- <div class="modal-footer flex-column">
798
- <div class="d-flex w-100">
799
- <div class="flex-grow-1 text-left">
800
- <button type="button" class="k-button k-primary">...</button>
801
- </div>
802
- <div class="flex-grow-1 text-right">
803
- <button type="button" class="k-button k-secondary" data-cancel="modal">Cancel</button>
804
- </div>
805
- </div>
806
- </div>
807
- </div>
808
- </div>
809
- </div>
810
- `);
811
-
812
- // Add listener to dialog hide event
813
- this._editDialog.on('hidden.bs.modal', $.proxy(this._onEditPanelHidden, this));
814
-
815
- // Add listener to main button click event
816
- $('button.k-primary', this._editDialog).on('click', $.proxy(this._onSubmitBtClick, this));
817
-
818
- // Add listener to close/cancel buttons click event
819
- $('button[data-cancel="modal"]', this._editDialog).on('click', $.proxy(this._onCancelBtClick, this));
820
-
821
- // Append edit dialog to main html
822
- this._widgetHtml.append(this._editDialog);
823
- }
824
-
825
- // Return component
826
- return this._widgetHtml;
827
- }
828
-
829
- /**
830
- * Initialize widget.
831
- * @override
832
- */
833
- _initialize()
834
- {
835
- let columns = [];
836
- for (let subConfigParam of this._data.defaultListItem)
837
- {
838
- let col = {
839
- field: subConfigParam.name,
840
- title: subConfigParam.label,
841
- width: 120
842
- }
843
-
844
- // Display V or X for booleans
845
- if (typeof subConfigParam.value === 'boolean')
846
- col.template = `#= ${subConfigParam.name} ? '<i class="fas fa-check"></i>' : '<i class="fas fa-times"></i>' #`;
847
-
848
- // Hide passwords
849
- if (subConfigParam.type == 'TextInput' && subConfigParam.attributes != null && subConfigParam.attributes.type == 'password')
850
- col.template = `#= '•'.repeat(data.${subConfigParam.name}.length) #`;
851
-
852
- columns.push(col);
853
- }
854
-
855
- // Initialize grid
856
- let gridHtml = this._widgetHtml.find(`#${$.escapeSelector(this._data.name)}`);
857
-
858
- gridHtml.kendoGrid({
859
- resizable: true,
860
- selectable: this._data.editable ? 'row' : false,
861
- change: $.proxy(this._onGridSelectionChange, this),
862
- columns: columns,
863
- noRecords: {
864
- template: 'No items.'
865
- }
866
- });
867
-
868
- // Save ref. to widget
869
- this._gridWidget = gridHtml.data('kendoGrid');
870
-
871
- // Show tootip if grid's cell content exceeds cell width (ellipsis is displayed by Kendo Grid)
872
- gridHtml.kendoTooltip({
873
- filter: 'td',
874
- show: function(e) {
875
- // Never show tooltip...
876
- this.content.parent().css('visibility', 'hidden');
877
-
878
- // ...unless content is returned (see below) due to cell width being exceeded
879
- if (this.content.text() != '')
880
- this.content.parent().css('visibility', 'visible');
881
- },
882
- hide: function() {
883
- this.content.parent().css('visibility', 'hidden');
884
- },
885
- content: function(e) {
886
- let element = e.target[0];
887
- if (element.offsetWidth < element.scrollWidth)
888
- return e.target.text();
889
- else
890
- return '';
891
- }
892
- });
893
-
894
- /*
895
- // Initialize button tooltips
896
- this._widgetHtml.kendoTooltip({
897
- filter: 'button',
898
- content: function(e) {
899
- return `<div class="help-tooltip">${e.target.data('title')}</div>`;
900
- }
901
- });
902
- */
903
-
904
- // Add button listeners
905
- if (this._data.editable)
906
- {
907
- this._addButton.click($.proxy(this._onAddClick, this));
908
- this._editButton.click($.proxy(this._onEditClick, this));
909
- this._removeButton.click($.proxy(this._onRemoveClick, this));
910
- }
911
-
912
- // Proceed with initialization
913
- super._initialize();
914
- }
915
-
916
- /**
917
- * Set widget's datasource.
918
- * @override
919
- */
920
- _setWidgetValue()
921
- {
922
- let dataSource = new kendo.data.DataSource({
923
- data: this._data.listValues
924
- });
925
-
926
- // Read current horizontal scroll value
927
- const scrollLeft = $('.k-grid-content', this._gridWidget.wrapper).scrollLeft();
928
-
929
- // Clear grid selection if any
930
- this._gridWidget.clearSelection();
931
-
932
- // Set updated grid's datasource
933
- this._gridWidget.setDataSource(dataSource);
934
-
935
- // Set horizontal scroll
936
- $('.k-grid-content', this._gridWidget.wrapper).scrollLeft(scrollLeft);
937
- }
938
-
939
- /**
940
- * Set widget's disabled state.
941
- * @override
942
- */
943
- _setWidgetEditEnabled()
944
- {
945
- if (this._data.editable)
946
- {
947
- // Deselect item
948
- this._gridWidget.clearSelection();
949
-
950
- // Enable/disable grid
951
- this._gridWidget.wrapper.attr('disabled', !this._editEnabled);
952
-
953
- // Enable "Add" button
954
- if (this._editEnabled)
955
- this._addButton.attr('disabled', false);
956
-
957
- // Disable all buttons
958
- else
959
- {
960
- this._addButton.attr('disabled', true);
961
- this._editButton.attr('disabled', true);
962
- this._removeButton.attr('disabled', true);
963
- }
964
- }
965
- }
966
-
967
- _onGridSelectionChange(e)
968
- {
969
- let selectedRows = this._gridWidget.select();
970
- let selectedDataItems = [];
971
-
972
- for (let i = 0; i < selectedRows.length; i++)
973
- {
974
- let dataItem = this._gridWidget.dataItem(selectedRows[i]);
975
- selectedDataItems.push(dataItem);
976
- }
977
-
978
- // Enable/disable edit button
979
- if (this._editButton)
980
- this._editButton.prop('disabled', selectedDataItems.length == 0);
981
-
982
- // Enable/disable remove button
983
- if (this._removeButton)
984
- {
985
- // Always disable button if no list item is selected
986
- this._removeButton.prop('disabled', selectedDataItems.length == 0);
987
-
988
- // Also disable button if denyEmpty == true and just one item remains in the list
989
- if (this._data.denyEmpty)
990
- this._removeButton.prop('disabled', this._data.listItems.length <= 1);
991
- }
992
- }
993
-
994
- _onRemoveClick()
995
- {
996
- let selectedIndex = this._gridWidget.select().index();
997
-
998
- // Remove item from list
999
- this._data.removeListItem(selectedIndex);
1000
-
1001
- // Regenerate datagrid's datasource
1002
- this._setWidgetValue();
1003
- }
1004
-
1005
- _onAddClick()
1006
- {
1007
- // Clone default item and add to list
1008
- let newListItem = [];
1009
- for (let subCP of this._data.defaultListItem)
1010
- newListItem.push(subCP.clone(true));
1011
-
1012
- // Create edit popup
1013
- this._openEditPanel(newListItem);
1014
- }
1015
-
1016
- _onEditClick()
1017
- {
1018
- let selectedIndex = this._gridWidget.select().index();
1019
-
1020
- // Clone selected item and add to list
1021
- let clonedListItem = [];
1022
- for (let subCP of this._data.listItems[selectedIndex])
1023
- clonedListItem.push(subCP.clone(true));
1024
-
1025
- // Create edit popup
1026
- this._openEditPanel(clonedListItem, selectedIndex);
1027
- }
1028
-
1029
- _openEditPanel(subConfigParamsArray, editIndex = -1)
1030
- {
1031
- // Check if this configuration item is inside a modal window;
1032
- // if yes, the edit panel (which is a modal as well) must be configured to remove the dark background
1033
- if ($(this).parents('.modal').length > 0)
1034
- $('.modal', $(this)).attr('data-backdrop', false);
1035
-
1036
- // Create dialog content
1037
- this._itemEditor = new _widgets_list_item_editor__WEBPACK_IMPORTED_MODULE_2__["ListItemEditor"]();
1038
- this._itemEditor.data = subConfigParamsArray;
1039
- this._itemEditor.index = editIndex;
1040
-
1041
- let itemEditor = $(this._itemEditor);
1042
-
1043
- // Append content to dialog
1044
- $('.modal-body', this._editDialog).append(itemEditor);
1045
-
1046
- // Set dialog main button text
1047
- $('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');
1048
-
1049
- // Display dialog
1050
- this._editDialog.modal('show');
1051
- }
1052
-
1053
- _onSubmitBtClick()
1054
- {
1055
- if (this._itemEditor.validate())
1056
- {
1057
- let data = this._itemEditor.data;
1058
- let index = this._itemEditor.index;
1059
-
1060
- // Hide modal
1061
- this._editDialog.modal('hide');
1062
-
1063
- // Complete editing
1064
- this._onEditComplete(data, index);
1065
- }
1066
- }
1067
-
1068
- _onCancelBtClick()
1069
- {
1070
- // Hide modal
1071
- this._editDialog.modal('hide');
1072
- }
1073
-
1074
- _onEditPanelHidden(e)
1075
- {
1076
- // Remove content from dialog
1077
- this._itemEditor.remove();
1078
-
1079
- // Set dialog main button text
1080
- $('button.k-primary', this._editDialog).html('...');
1081
-
1082
- this._itemEditor = null;
1083
- }
1084
-
1085
- _onEditComplete(listItem, editIndex)
1086
- {
1087
- // An existing list item was updated
1088
- if (editIndex > -1)
1089
- this._data.updateListItem(listItem, editIndex);
1090
-
1091
- // A new list item was added; add it to the configuration parameter
1092
- else
1093
- this._data.addListItem(listItem);
1094
-
1095
- // Regenerate datagrid's datasource
1096
- this._setWidgetValue();
1097
- }
1098
- }
1099
-
1100
- // DEFINE COMPONENT
1101
- if (!window.customElements.get('config-grid'))
1102
- window.customElements.define('config-grid', ConfigGrid);
1103
-
1104
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1105
-
1106
- /***/ }),
1107
-
1108
- /***/ "./src/components/uibuilder/config-label.js":
1109
- /*!**************************************************!*\
1110
- !*** ./src/components/uibuilder/config-label.js ***!
1111
- \**************************************************/
1112
- /*! exports provided: ConfigLabel */
1113
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1114
-
1115
- "use strict";
1116
- __webpack_require__.r(__webpack_exports__);
1117
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigLabel", function() { return ConfigLabel; });
1118
- class ConfigLabel extends HTMLElement
1119
- {
1120
- constructor()
1121
- {
1122
- super();
1123
-
1124
- this.setAttribute('class','config-label');
1125
- }
1126
-
1127
- set value(val)
1128
- {
1129
- if (typeof val === 'boolean')
1130
- this.innerHTML = (val ? 'true' : 'false');
1131
- else if (typeof val === 'number')
1132
- this.innerHTML = (val ? val : 0);
1133
- else
1134
- this.innerHTML = (val != '' ? val : '&mdash;');
1135
- }
1136
-
1137
- get value()
1138
- {
1139
- return this.textContent;
1140
- }
1141
- }
1142
-
1143
- // DEFINE COMPONENT
1144
- if (!window.customElements.get('config-label'))
1145
- window.customElements.define('config-label', ConfigLabel);
1146
-
1147
-
1148
- /***/ }),
1149
-
1150
- /***/ "./src/components/uibuilder/config-numeric-stepper.js":
1151
- /*!************************************************************!*\
1152
- !*** ./src/components/uibuilder/config-numeric-stepper.js ***!
1153
- \************************************************************/
1154
- /*! exports provided: ConfigNumericStepper */
1155
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1156
-
1157
- "use strict";
1158
- __webpack_require__.r(__webpack_exports__);
1159
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigNumericStepper", function() { return ConfigNumericStepper; });
1160
- /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1161
- /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1162
-
1163
-
1164
-
1165
- class ConfigNumericStepper extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1166
- {
1167
- constructor(configParam, editEnabled, inDialog)
1168
- {
1169
- super(configParam, editEnabled, inDialog);
1170
- }
1171
-
1172
- /**
1173
- * Create widget to render the ConfigParameter value.
1174
- * If parameter is not editable, a simple label is used.
1175
- * @override
1176
- */
1177
- _generateInnerWidget()
1178
- {
1179
- if (this._data.editable)
1180
- {
1181
- // Set widget configuration
1182
- let config = {
1183
- type: 'number',
1184
- class: 'form-control',
1185
- id: this._data.name,
1186
- name: this._data.name,
1187
- 'data-role': 'numerictextbox',
1188
- 'data-required-msg': 'Required',
1189
- 'data-format': '#',
1190
- required: 'required',
1191
- };
1192
-
1193
- // Set widget attributes (see parent class)
1194
- this._setWidgetAttributes(config);
1195
-
1196
- // Set additional widget attributes based on validation rules (see parent class)
1197
- this._setWidgetValidationAttributes(config);
1198
-
1199
- // Create widget's html
1200
- this._widgetHtml = $('<input>', config);
1201
- }
1202
- else
1203
- this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1204
-
1205
- // Return component
1206
- return this._widgetHtml;
1207
- }
1208
-
1209
- /**
1210
- * Initialize widget.
1211
- * @override
1212
- */
1213
- _initialize()
1214
- {
1215
- if (this._data.editable)
1216
- {
1217
- // Initialize kendo widget
1218
- kendo.init(this._widgetHtml);
1219
-
1220
- // Save ref. to widget
1221
- this._innerWidget = this._widgetHtml.data('kendoNumericTextBox');
1222
-
1223
- // Enable value commit binding
1224
- this._innerWidget.bind('change', $.proxy(this._onValueInput, this));
1225
- }
1226
-
1227
- // Proceed with initialization
1228
- super._initialize();
1229
- }
1230
-
1231
- /**
1232
- * Set widget's value.
1233
- * If parameter is not editable, the label text is set.
1234
- * @override
1235
- */
1236
- _setWidgetValue()
1237
- {
1238
- if (this._data.editable)
1239
- this._innerWidget.value(this._data.value);
1240
- else
1241
- this._widgetHtml.value = this._data.value;
1242
-
1243
- // Trigger event
1244
- this._triggerEvent();
1245
- }
1246
-
1247
- /**
1248
- * Set widget's disabled state.
1249
- * @override
1250
- */
1251
- _setWidgetEditEnabled()
1252
- {
1253
- if (this._data.editable)
1254
- this._innerWidget.enable(this._editEnabled);
1255
- }
1256
-
1257
- /**
1258
- * Update Configuration Parameter value.
1259
- * @override
1260
- */
1261
- _onValueInput(e)
1262
- {
1263
- // Update Configuration Parameter to new value
1264
- this._data.value = Number(this._innerWidget.value());
1265
-
1266
- // Trigger event
1267
- this._triggerEvent();
1268
- }
1269
- }
1270
-
1271
- // DEFINE COMPONENT
1272
- if (!window.customElements.get('config-numeric-stepper'))
1273
- window.customElements.define('config-numeric-stepper', ConfigNumericStepper);
1274
-
1275
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1276
-
1277
- /***/ }),
1278
-
1279
- /***/ "./src/components/uibuilder/config-text-input.js":
1280
- /*!*******************************************************!*\
1281
- !*** ./src/components/uibuilder/config-text-input.js ***!
1282
- \*******************************************************/
1283
- /*! exports provided: ConfigTextInput */
1284
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1285
-
1286
- "use strict";
1287
- __webpack_require__.r(__webpack_exports__);
1288
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigTextInput", function() { return ConfigTextInput; });
1289
- /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1290
- /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1291
-
1292
-
1293
-
1294
- class ConfigTextInput extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1295
- {
1296
- constructor(configParam, editEnabled, inDialog)
1297
- {
1298
- super(configParam, editEnabled, inDialog);
1299
- }
1300
-
1301
- /**
1302
- * Create widget to render the ConfigParameter value.
1303
- * If parameter is not editable, a simple label is used.
1304
- * @override
1305
- */
1306
- _generateInnerWidget()
1307
- {
1308
- if (this._data.editable)
1309
- {
1310
- // Set widget configuration
1311
- let config = {
1312
- type: 'text',
1313
- class: 'form-control k-textbox',
1314
- id: this._data.name,
1315
- name: this._data.name,
1316
- autocomplete: 'off',
1317
- };
1318
-
1319
- // Set widget attributes
1320
- this._setWidgetAttributes(config);
1321
-
1322
- // Set additional widget attributes based on validation rules
1323
- this._setWidgetValidationAttributes(config);
1324
-
1325
- // Create widget's html
1326
- this._widgetHtml = $('<input>', config);
1327
-
1328
- // Enable value commit binding
1329
- this._widgetHtml.on('change', $.proxy(this._onValueInput, this));
1330
- }
1331
- else
1332
- this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1333
-
1334
- // Return component
1335
- return this._widgetHtml;
1336
- }
1337
-
1338
- /**
1339
- * Set widget's value.
1340
- * If parameter is not editable, the label text is set.
1341
- * @override
1342
- */
1343
- _setWidgetValue()
1344
- {
1345
- if (this._data.editable)
1346
- this._widgetHtml.val(this._data.value);
1347
- else
1348
- this._widgetHtml.value = this._data.value;
1349
-
1350
- // Trigger event
1351
- this._triggerEvent();
1352
- }
1353
-
1354
- /**
1355
- * Set widget's disabled state.
1356
- * @override
1357
- */
1358
- _setWidgetEditEnabled()
1359
- {
1360
- if (this._data.editable)
1361
- this._widgetHtml.attr('disabled', !this._editEnabled);
1362
- }
1363
-
1364
- /**
1365
- * Update Configuration Parameter value.
1366
- * @override
1367
- */
1368
- _onValueInput(e)
1369
- {
1370
- // Update Configuration Parameter to new value
1371
- this._data.value = this._widgetHtml.val();
1372
-
1373
- // Trigger event
1374
- this._triggerEvent();
1375
- }
1376
- }
1377
-
1378
- // DEFINE COMPONENT
1379
- if (!window.customElements.get('config-text-input'))
1380
- window.customElements.define('config-text-input', ConfigTextInput);
1381
-
1382
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1383
-
1384
- /***/ }),
1385
-
1386
- /***/ "./src/components/uibuilder/config-vector-3d.js":
1387
- /*!******************************************************!*\
1388
- !*** ./src/components/uibuilder/config-vector-3d.js ***!
1389
- \******************************************************/
1390
- /*! exports provided: ConfigVector3D */
1391
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1392
-
1393
- "use strict";
1394
- __webpack_require__.r(__webpack_exports__);
1395
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigVector3D", function() { return ConfigVector3D; });
1396
- /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1397
- /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1398
- /* 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");
1399
-
1400
-
1401
-
1402
-
1403
- class ConfigVector3D extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1404
- {
1405
- constructor(configParam, editEnabled, inDialog)
1406
- {
1407
- super(configParam, editEnabled, inDialog);
1408
- }
1409
-
1410
- /**
1411
- * Create widget to render the ConfigParameter value.
1412
- * If parameter is not editable, a simple label is used.
1413
- * @override
1414
- */
1415
- _generateInnerWidget()
1416
- {
1417
- if (this._data.editable)
1418
- {
1419
- // Create widget's html
1420
- this._widgetHtml = new _widgets_vector_3d_input__WEBPACK_IMPORTED_MODULE_2__["Vector3DInput"](this._data.name, this._data.validator == 'aoi');
1421
-
1422
- // Set widget attributes
1423
- this._setWidgetAttributes(this._widgetHtml);
1424
-
1425
- // Enable value commit binding
1426
- $(this._widgetHtml).on('change', $.proxy(this._onValueInput, this));
1427
- }
1428
- else
1429
- this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1430
-
1431
- // Return component
1432
- return this._widgetHtml;
1433
- }
1434
-
1435
- /**
1436
- * Set widget's value.
1437
- * If parameter is not editable, the label text is set.
1438
- * @override
1439
- */
1440
- _setWidgetValue()
1441
- {
1442
- this._widgetHtml.value = this._data.value;
1443
-
1444
- // Trigger event
1445
- this._triggerEvent();
1446
- }
1447
-
1448
- /**
1449
- * Set widget's disabled state.
1450
- * @override
1451
- */
1452
- _setWidgetEditEnabled()
1453
- {
1454
- if (this._data.editable)
1455
- {
1456
- $(this._widgetHtml).attr('disabled', !this._editEnabled);
1457
- }
1458
- }
1459
-
1460
- /**
1461
- * Update Configuration Parameter value.
1462
- * @override
1463
- */
1464
- _onValueInput(e)
1465
- {
1466
- // Update Configuration Parameter to new value
1467
- this._data.value = this._widgetHtml.value;
1468
-
1469
- // Trigger event
1470
- this._triggerEvent();
1471
- }
1472
- }
1473
-
1474
- // DEFINE COMPONENT
1475
- if (!window.customElements.get('config-vector-3d'))
1476
- window.customElements.define('config-vector-3d', ConfigVector3D);
1477
-
1478
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1479
-
1480
- /***/ }),
1481
-
1482
- /***/ "./src/components/uibuilder/widgets/list-item-editor.js":
1483
- /*!**************************************************************!*\
1484
- !*** ./src/components/uibuilder/widgets/list-item-editor.js ***!
1485
- \**************************************************************/
1486
- /*! exports provided: ListItemEditor */
1487
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1488
-
1489
- "use strict";
1490
- __webpack_require__.r(__webpack_exports__);
1491
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ListItemEditor", function() { return ListItemEditor; });
1492
- /* 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");
1493
-
1494
-
1495
- class ListItemEditor extends HTMLElement
1496
- {
1497
- constructor()
1498
- {
1499
- super();
1500
- }
1501
-
1502
- set data(subConfigParamsArray)
1503
- {
1504
- this._data = subConfigParamsArray;
1505
-
1506
- this._buildView();
1507
- }
1508
-
1509
- get data()
1510
- {
1511
- return this._data;
1512
- }
1513
-
1514
- set index(index)
1515
- {
1516
- this._index = index;
1517
- }
1518
-
1519
- get index()
1520
- {
1521
- return this._index;
1522
- }
1523
-
1524
- _buildView()
1525
- {
1526
- // Generate container form
1527
- this._form = $('<form>', {});
1528
-
1529
- // Append form
1530
- $(this).append(this._form);
1531
-
1532
- // Generate form fields
1533
- for (let configParam of this._data)
1534
- {
1535
- // Create form item
1536
- let formItem = _utils_uibuilder_config_form_item_factory__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItemFactory"].create(configParam, true, true);
1537
- formItem.data = configParam;
1538
-
1539
- // Add form item to form
1540
- this._form.append(formItem);
1541
- }
1542
-
1543
- // Initialize kendo validation on form
1544
- this._validator = this._form.kendoValidator({
1545
- validateOnBlur: true,
1546
- rules: {
1547
- // Add rule to validate AOI form items?
1548
- // (see: https://demos.telerik.com/kendo-ui/validator/custom-validation)
1549
- aoi: function (input) {
1550
- if (input.is('[data-aoi-msg]') && input.val() != '')
1551
- {
1552
- if (input.val() == '0,0,0')
1553
- return false;
1554
- }
1555
-
1556
- return true;
1557
- }
1558
- }
1559
- }).data('kendoValidator');
1560
- }
1561
-
1562
- validate()
1563
- {
1564
- return this._validator.validate();
1565
- }
1566
- }
1567
-
1568
- // DEFINE COMPONENT
1569
- if (!window.customElements.get('list-item-editor'))
1570
- window.customElements.define('list-item-editor', ListItemEditor);
1571
-
1572
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1573
-
1574
- /***/ }),
1575
-
1576
- /***/ "./src/components/uibuilder/widgets/vector-3d-input.js":
1577
- /*!*************************************************************!*\
1578
- !*** ./src/components/uibuilder/widgets/vector-3d-input.js ***!
1579
- \*************************************************************/
1580
- /*! exports provided: Vector3DInput */
1581
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1582
-
1583
- "use strict";
1584
- __webpack_require__.r(__webpack_exports__);
1585
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3DInput", function() { return Vector3DInput; });
1586
- class Vector3DInput extends HTMLElement
1587
- {
1588
- constructor(id, isValidable)
1589
- {
1590
- super();
1591
-
1592
- this.id = id;
1593
- this.name = id;
1594
-
1595
- this._isValidable = isValidable;
1596
-
1597
- this._initialize();
1598
- }
1599
-
1600
- set enableClear(value)
1601
- {
1602
- if (value)
1603
- this._clearButton.show();
1604
- else
1605
- this._clearButton.hide();
1606
- }
1607
-
1608
- set allowNegative(value)
1609
- {
1610
- if (value)
1611
- {
1612
- this._widgetX.setOptions( {min: null} );
1613
- this._widgetY.setOptions( {min: null} );
1614
- this._widgetZ.setOptions( {min: null} );
1615
- }
1616
- }
1617
-
1618
- set value(val)
1619
- {
1620
- var coords = val.split(',');
1621
-
1622
- if (coords.length >= 1)
1623
- this._widgetX.value(coords[0]);
1624
-
1625
- if (coords.length >= 2)
1626
- this._widgetY.value(coords[1]);
1627
-
1628
- if (coords.length >= 3)
1629
- this._widgetZ.value(coords[2]);
1630
-
1631
- if (this._isValidable)
1632
- this._inputVal.val(this.value);
1633
- }
1634
-
1635
- get value()
1636
- {
1637
- if (this._widgetX.value() == null && this._widgetY.value() == null && this._widgetZ.value() == null)
1638
- return '';
1639
- else
1640
- return this._widgetX.value() + ',' + this._widgetY.value() + ',' + this._widgetZ.value();
1641
- }
1642
-
1643
- _initialize()
1644
- {
1645
- // Generate container form
1646
- this._container = $('<div>', {
1647
- class: 'form-inline'
1648
- });
1649
-
1650
- // Append container
1651
- $(this).append(this._container);
1652
-
1653
- // Set inputs configuration
1654
- let configHtml = {
1655
- type: 'number',
1656
- class: 'form-control short-4',
1657
- };
1658
-
1659
- // Set widget configuration
1660
- let configWidget = {
1661
- min: 0,
1662
- spinners: false,
1663
- format: '#.######',
1664
- decimals: 6,
1665
- round: false,
1666
- spinners: false,
1667
- restrictDecimals: false,
1668
- change: $.proxy(this._onChange, this)
1669
- };
1670
-
1671
- // Create widgets
1672
- this._inputX = $('<input>', configHtml);
1673
- this._container.append(this._inputX);
1674
- this._widgetX = this._inputX.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1675
-
1676
- this._container.append('<span class="px-1">,</span>');
1677
-
1678
- this._inputY = $('<input>', configHtml);
1679
- this._container.append(this._inputY);
1680
- this._widgetY = this._inputY.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1681
-
1682
- this._container.append('<span class="px-1">,</span>');
1683
-
1684
- this._inputZ = $('<input>', configHtml);
1685
- this._container.append(this._inputZ);
1686
- this._widgetZ = this._inputZ.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1687
-
1688
- this._container.append('<span class="px-1"></span>'); // Additional spacer
1689
-
1690
- // Create invisible field to apply overall validation
1691
- if (this._isValidable)
1692
- {
1693
- this._inputVal = $('<input>', {name: `${this.name}-custom-validate`, 'data-aoi-msg': 'Values can\'t all be 0'});
1694
- this._container.append(this._inputVal);
1695
- this._container.append(`<span class="k-invalid-msg" data-for="${this.name}-custom-validate"></span>`)
1696
- this._inputVal.hide();
1697
- }
1698
-
1699
- // Create and append Clear button
1700
- this._clearButton = $('<button>', {type: 'button', class: 'k-button k-secondary my-1', title: 'Clear'}).append($('<i class="fas fa-times"></i>'));
1701
- this._clearButton.on('click', $.proxy(this._onClearClick, this));
1702
- this._container.append(this._clearButton);
1703
-
1704
- // Hide button by default
1705
- this._clearButton.hide();
1706
- }
1707
-
1708
- _onChange()
1709
- {
1710
- // Empty strings are not allowed
1711
- if (this._widgetX.value() == null)
1712
- this._widgetX.value(0);
1713
-
1714
- if (this._widgetY.value() == null)
1715
- this._widgetY.value(0);
1716
-
1717
- if (this._widgetZ.value() == null)
1718
- this._widgetZ.value(0);
1719
-
1720
- this._dispatchCommit();
1721
- }
1722
-
1723
- _onClearClick()
1724
- {
1725
- this._widgetX.value('');
1726
- this._widgetY.value('');
1727
- this._widgetZ.value('');
1728
-
1729
- this._dispatchCommit();
1730
- }
1731
-
1732
- _dispatchCommit()
1733
- {
1734
- if (this._isValidable)
1735
- this._inputVal.val(this.value);
1736
-
1737
- this.dispatchEvent(new Event('change'));
1738
- }
1739
- }
1740
-
1741
- // DEFINE COMPONENT
1742
- if (!window.customElements.get('vector-3d-input'))
1743
- window.customElements.define('vector-3d-input', Vector3DInput);
1744
-
1745
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1746
-
1747
- /***/ }),
1748
-
1749
- /***/ "./src/utils/uibuilder/config-form-item-factory.js":
1750
- /*!*********************************************************!*\
1751
- !*** ./src/utils/uibuilder/config-form-item-factory.js ***!
1752
- \*********************************************************/
1753
- /*! exports provided: ConfigFormItemFactory */
1754
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1755
-
1756
- "use strict";
1757
- __webpack_require__.r(__webpack_exports__);
1758
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigFormItemFactory", function() { return ConfigFormItemFactory; });
1759
- /* 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");
1760
- /* 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");
1761
- /* 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");
1762
- /* 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");
1763
- /* 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");
1764
- /* harmony import */ var _components_uibuilder_config_grid__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../components/uibuilder/config-grid */ "./src/components/uibuilder/config-grid.js");
1765
- /* 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");
1766
- /* 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");
1767
-
1768
-
1769
-
1770
-
1771
-
1772
-
1773
-
1774
-
1775
-
1776
-
1777
- class ConfigFormItemFactory
1778
- {
1779
- static create(configParam, editEnabled, inDialog = false)
1780
- {
1781
- switch (configParam.type)
1782
- {
1783
- case 'TextInput':
1784
- return new _components_uibuilder_config_text_input__WEBPACK_IMPORTED_MODULE_2__["ConfigTextInput"](configParam, editEnabled, inDialog);
1785
- break;
1786
-
1787
- case 'CheckBox':
1788
- return new _components_uibuilder_config_check_box__WEBPACK_IMPORTED_MODULE_3__["ConfigCheckBox"](configParam, editEnabled, inDialog);
1789
- break;
1790
-
1791
- case 'NumericStepper':
1792
- return new _components_uibuilder_config_numeric_stepper__WEBPACK_IMPORTED_MODULE_1__["ConfigNumericStepper"](configParam, editEnabled, inDialog);
1793
- break;
1794
-
1795
- case 'ComboBox':
1796
- return new _components_uibuilder_config_drop_down_list__WEBPACK_IMPORTED_MODULE_4__["ConfigDropDownList"](configParam, editEnabled, inDialog);
1797
- break;
1798
-
1799
- case 'DataGrid':
1800
- return new _components_uibuilder_config_grid__WEBPACK_IMPORTED_MODULE_5__["ConfigGrid"](configParam, editEnabled, inDialog);
1801
- break;
1802
-
1803
- case 'DualList':
1804
- return new _components_uibuilder_config_dual_list__WEBPACK_IMPORTED_MODULE_6__["ConfigDualList"](configParam, editEnabled, inDialog);
1805
- break;
1806
-
1807
- case 'Vector3D':
1808
- return new _components_uibuilder_config_vector_3d__WEBPACK_IMPORTED_MODULE_7__["ConfigVector3D"](configParam, editEnabled, inDialog);
1809
- break;
1810
-
1811
- default:
1812
- return new _components_uibuilder_config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"](configParam, editEnabled, inDialog); // Will log an error for missing form item type
1813
- }
1814
- }
1815
- }
1816
-
1817
-
1818
- /***/ }),
1819
-
1820
- /***/ "./src/utils/uibuilder/config-interface-builder.js":
1821
- /*!*********************************************************!*\
1822
- !*** ./src/utils/uibuilder/config-interface-builder.js ***!
1823
- \*********************************************************/
1824
- /*! exports provided: ConfigInterfaceBuilder */
1825
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1826
-
1827
- "use strict";
1828
- __webpack_require__.r(__webpack_exports__);
1829
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigInterfaceBuilder", function() { return ConfigInterfaceBuilder; });
1830
- /* harmony import */ var _configuration_parameter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./configuration-parameter */ "./src/utils/uibuilder/configuration-parameter.js");
1831
- /* 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");
1832
-
1833
-
1834
-
1835
- class ConfigInterfaceBuilder
1836
- {
1837
- constructor()
1838
- {
1839
- // Set some constants
1840
- this.TAB_PREFIX = 'tab-'
1841
- this.TAB_PANE_PREFIX = 'tabpane-';
1842
- this.SEPARATOR_BEFORE = 'before';
1843
- this.SEPARATOR_AFTER = 'after';
1844
- }
1845
-
1846
- dump(modifiedOnly = false)
1847
- {
1848
- let dumpStr = '';
1849
-
1850
- for (let cp of this._configParams)
1851
- {
1852
- if (modifiedOnly)
1853
- {
1854
- if (cp.isModified)
1855
- dumpStr += cp.toString() + '\n';
1856
- }
1857
- else
1858
- dumpStr += cp.toString() + '\n';
1859
- }
1860
-
1861
- console.log(dumpStr);
1862
- }
1863
-
1864
- buildInterface(data, mainContainerId, disableEdit = false, tabSuffix = '')
1865
- {
1866
- this._mainContainerId = mainContainerId;
1867
- this._configParams = new Array();
1868
- this._validator = null;
1869
-
1870
- let hasNewFormItem = false;
1871
-
1872
- //console.log(data.getDump())
1873
-
1874
- for (let i = 0; i < data.size(); i++)
1875
- {
1876
- // PARSE DATA
1877
-
1878
- let configParam = _configuration_parameter__WEBPACK_IMPORTED_MODULE_0__["ConfigurationParameter"].fromSfsObject(data.get(i));
1879
- this._configParams.push(configParam);
1880
-
1881
- // Get tab and tab pane id from group id
1882
- const tabId = this.TAB_PREFIX + configParam.categoryId + (tabSuffix ? '_' + tabSuffix : '');
1883
- const tabPaneId = this.TAB_PANE_PREFIX + configParam.categoryId + (tabSuffix ? '_' + tabSuffix : '');
1884
-
1885
- // BUILD INTERFACE :: TABS
1886
-
1887
- // Check if a tab specific for this group already exists inside the mainContainer: if not, create it
1888
- // (a tab already exists if it was created in a previous loop)
1889
- let tab = $(`#${mainContainerId} > #tabs #${tabId}`);
1890
-
1891
- if (tab.length == 0)
1892
- {
1893
- // Create tab for tab pane
1894
- tab = $('<li>', {class: 'nav-item'});
1895
- tab.append($('<a>', {
1896
- class: 'nav-link' + (i == 0 ? ' active' : ''),
1897
- id: tabId,
1898
- 'data-toggle': 'tab',
1899
- href: '#' + tabPaneId,
1900
- role: 'tab',
1901
- 'aria-controls': tabPaneId,
1902
- 'aria-selected': (i == 0 ? 'true' : 'false'),
1903
- html: configParam.category,
1904
- }));
1905
-
1906
- // Add tab to container
1907
- $(`#${mainContainerId} > #tabs`).append(tab);
1908
- }
1909
-
1910
- // BUILD INTERFACE :: TAB PANES
1911
-
1912
- // Check if a tab pane specific for this group already exists inside the mainContainer: if not, create it
1913
- // (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)
1914
- let tabPane = $(`#${mainContainerId} > #tabPanels > #${tabPaneId}`);
1915
-
1916
- if (tabPane.length == 0)
1917
- {
1918
- // Create tab pane
1919
- tabPane = $('<div>', {
1920
- class: 'tab-pane' + (i == 0 ? ' show active' : ''),
1921
- id: tabPaneId,
1922
- role: 'tabpanel',
1923
- 'aria-labelledby': tabId,
1924
- 'data-dynamic': 'true',
1925
- });
1926
-
1927
- // Add tab pane to container
1928
- $(`#${mainContainerId} > #tabPanels`).append(tabPane);
1929
- }
1930
-
1931
- // BUILD INTERFACE :: TAB PANES' FORM
1932
-
1933
- // Check if a form already exists inside the tab pane: if not, create it
1934
- let form = tabPane.find('form');
1935
-
1936
- if (form.length == 0)
1937
- {
1938
- // Create form
1939
- form = $('<form>', {
1940
- class: '',
1941
- autocomplete: 'off'
1942
- });
1943
-
1944
- // 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)
1945
- form.append(
1946
- $('<fieldset>', {
1947
- class: ''
1948
- })
1949
- );
1950
-
1951
- // Add form to tab pane
1952
- tabPane.prepend(form);
1953
- }
1954
-
1955
- // Get fieldset, which is the actual form items container
1956
- let fieldset = form.find('fieldset');
1957
-
1958
- // BUILD INTERFACE :: TAB PANES' FORM ITEMS
1959
-
1960
- // Check if form item already exists in fieldset; if yes, just update its data
1961
- let formItem = fieldset.find(`#form-item-${$.escapeSelector(configParam.name)}`);
1962
-
1963
- if (formItem.length == 0)
1964
- {
1965
- hasNewFormItem = true;
1966
-
1967
- formItem = _config_form_item_factory__WEBPACK_IMPORTED_MODULE_1__["ConfigFormItemFactory"].create(configParam, !disableEdit);
1968
-
1969
- // Add separator before
1970
- if (configParam.separator != null && configParam.separator.pos == 'before')
1971
- fieldset.append(this._buildSeparator(configParam.separator));
1972
-
1973
- // Add form item to form
1974
- fieldset.append(formItem);
1975
-
1976
- // Add separator after
1977
- if (configParam.separator != null && configParam.separator.pos == 'after')
1978
- fieldset.append(this._buildSeparator(configParam.separator));
1979
- }
1980
- else
1981
- formItem[0].data = configParam;
1982
- }
1983
-
1984
- // Add listener to show help tooltips
1985
- let allTabPanes = $(`#${mainContainerId} > #tabPanels > div.tab-pane`);
1986
- allTabPanes.kendoTooltip({
1987
- filter: 'i[title].help',
1988
- position: 'right',
1989
- width: '250px',
1990
- content: function(e) {
1991
- return `<div class="help-tooltip">${e.target.data('title')}</div>`;
1992
- }
1993
- });
1994
-
1995
- // Initialize kendo validation on forms' main container
1996
- this._validator = $(`#${mainContainerId}`).kendoValidator({
1997
- validateOnBlur: true,
1998
- rules: {
1999
- // Add rule to validate AOI form items
2000
- // (see: https://demos.telerik.com/kendo-ui/validator/custom-validation)
2001
- aoi: function (input) {
2002
- if (input.is('[data-aoi-msg]') && input.val() != '')
2003
- {
2004
- if (input.val() == '0,0,0')
2005
- return false;
2006
- }
2007
-
2008
- return true;
2009
- }
2010
- }
2011
- }).data('kendoValidator');
2012
- }
2013
-
2014
- destroyInterface()
2015
- {
2016
- // Destroy all Kendo widgets in forms
2017
- kendo.destroy($(`#${this._mainContainerId} > #tabPanels > div.tab-pane > form`));
2018
-
2019
- // Remove all tabs
2020
- $(`#${this._mainContainerId} > #tabs`).empty();
2021
-
2022
- // Remove dynamic tab panes (tab panes created by Interface Builder)
2023
- $(`#${this._mainContainerId} > #tabPanels > div.tab-pane[data-dynamic="true"]`).remove();
2024
-
2025
- // Remove form inside static tab panes (predefined tab panes in html)
2026
- $(`#${this._mainContainerId} > #tabPanels > div.tab-pane > form`).remove();
2027
-
2028
- // Remove "active" class from static tab panes (otherwise this class messes with the tab navigator functioning)
2029
- $(`#${this._mainContainerId} > #tabPanels > div.tab-pane`).removeClass('active');
2030
- }
2031
-
2032
- disableInterface(disable)
2033
- {
2034
- // Enable/disable all config form items
2035
- $(`#${this._mainContainerId} *[id^='form-item-']`).prop('editEnabled', !disable);
2036
- }
2037
-
2038
- _buildSeparator(separator)
2039
- {
2040
- if (separator.text == null)
2041
- return $(`<hr class="config-form-separator">`);
2042
-
2043
- else
2044
- return $(`<label class="config-form-separator-label mb-3">${separator.text}</label>`);
2045
- }
2046
-
2047
- getChangedData()
2048
- {
2049
- let changes = new SFS2X.SFSArray();
2050
-
2051
- for (var cp of this._configParams)
2052
- {
2053
- if (cp.isModified)
2054
- changes.addSFSObject(cp.toSfsObject());
2055
- }
2056
-
2057
- return changes;
2058
- }
2059
-
2060
- resetIsModified()
2061
- {
2062
- for (let cp of this._configParams)
2063
- {
2064
- if (cp.isModified)
2065
- cp.resetIsModified();
2066
- }
2067
- }
2068
-
2069
- checkIsValid()
2070
- {
2071
- return this._validator.validate();
2072
- }
2073
-
2074
- resetValidation()
2075
- {
2076
- this._validator.hideMessages();
2077
-
2078
- // The method above doesn't remove the k-invalid classes and aria-invalid="true" attributes from inputs
2079
- // Let's do it manually
2080
- $(`#${this._mainContainerId} .k-invalid`).removeClass('k-invalid');
2081
- $(`#${this._mainContainerId} [aria-invalid="true"]`).removeAttr('aria-invalid');
2082
- }
2083
-
2084
- getConfigFormItem(configParamName)
2085
- {
2086
- let formItem = $(`#${this._mainContainerId}`).find(`#form-item-${$.escapeSelector(configParamName)}`);
2087
-
2088
- if (formItem.length > 0)
2089
- return formItem[0];
2090
- else
2091
- return null;
2092
- }
2093
-
2094
- activateFirstTabPanel()
2095
- {
2096
- let configParam = this._configParams[0];
2097
- const tabPaneId = this.TAB_PANE_PREFIX + configParam.categoryId;
2098
- let tabPane = $(`#${this._mainContainerId} > #tabPanels > #${tabPaneId}`);
2099
- tabPane.addClass('show active');
2100
- }
2101
- }
2102
-
2103
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
2104
-
2105
- /***/ }),
2106
-
2107
- /***/ "./src/utils/uibuilder/configuration-parameter.js":
2108
- /*!********************************************************!*\
2109
- !*** ./src/utils/uibuilder/configuration-parameter.js ***!
2110
- \********************************************************/
2111
- /*! exports provided: ConfigurationParameter */
2112
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
2113
-
2114
- "use strict";
2115
- __webpack_require__.r(__webpack_exports__);
2116
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigurationParameter", function() { return ConfigurationParameter; });
2117
- class ConfigurationParameter
2118
- {
2119
- static fromSfsObject(element)
2120
- {
2121
- let cp = new ConfigurationParameter();
2122
-
2123
- // Parse common data
2124
- cp.name = element.getUtfString('name');
2125
- cp.label = element.getUtfString('label');
2126
- cp.category = element.getUtfString('category');
2127
- cp.tooltip = element.getUtfString('tooltip');
2128
- cp.type = element.getUtfString('type');
2129
- cp.value = element.get('value');
2130
- cp.validator = element.getUtfString('validator');
2131
- cp.editable = (element.containsKey('edit') ? element.getBool('edit') : true);
2132
- cp.trigger = (element.containsKey('trigger') ? element.getBool('trigger') : false);
2133
- cp.triggerData = element.getSFSArray('triggerData');
2134
- cp.clientOnly = (element.containsKey('clientOnly') ? element.getBool('clientOnly') : false);
2135
- cp.dataProvider = element.getUtfString('dataProvider');
2136
-
2137
- // Parse component specific attributes
2138
- let tmpAttributes = element.getSFSObject('attributes');
2139
- if (tmpAttributes != null)
2140
- {
2141
- let attributes = {};
2142
-
2143
- let keys = tmpAttributes.getKeysArray();
2144
- for (let key of keys)
2145
- attributes[key] = tmpAttributes.get(key);
2146
-
2147
- cp.attributes = attributes;
2148
- }
2149
-
2150
- // Parse separator settings
2151
- let tmpSeparator = element.getSFSObject('separator');
2152
- if (tmpSeparator != null)
2153
- {
2154
- let separator = {};
2155
-
2156
- let keys1 = tmpSeparator.getKeysArray();
2157
- for (let key1 of keys1)
2158
- separator[key1] = tmpSeparator.get(key1);
2159
-
2160
- cp.separator = separator;
2161
- }
2162
-
2163
- // Parse default list item
2164
- let tmpDefaultListItem = element.getSFSArray('defaultListItem');
2165
- if (tmpDefaultListItem != null && tmpDefaultListItem.size() > 0)
2166
- {
2167
- let defaultListItem = [];
2168
-
2169
- for (let i = 0; i < tmpDefaultListItem.size(); i++)
2170
- defaultListItem.push(ConfigurationParameter.fromSfsObject(tmpDefaultListItem.getSFSObject(i)));
2171
-
2172
- cp.defaultListItem = defaultListItem;
2173
-
2174
- // Parse list values
2175
- let listValues = [];
2176
-
2177
- let tmpListValues = element.getSFSArray('listValues');
2178
- if (tmpListValues != null && tmpListValues.size() > 0)
2179
- {
2180
- for (let v = 0; v < tmpListValues.size(); v++)
2181
- {
2182
- let listValueObj = tmpListValues.getSFSObject(v);
2183
- let obj = {};
2184
-
2185
- let keys2 = listValueObj.getKeysArray();
2186
- for (let key2 of keys2)
2187
- obj[key2] = listValueObj.get(key2);
2188
-
2189
- listValues.push(obj);
2190
- }
2191
- }
2192
-
2193
- cp.listValues = listValues;
2194
-
2195
- // If we have a list, on the server-side items could be represented by a class
2196
- cp.clazz = element.getUtfString('clazz');
2197
-
2198
- // Avoid list to be emptied
2199
- cp.denyEmpty = (element.containsKey('denyEmpty') ? element.getBool('denyEmpty') : false);
2200
- }
2201
-
2202
- return cp;
2203
- }
2204
-
2205
- constructor()
2206
- {
2207
- /* CONSTANTS */
2208
- this.DEFAULT_CATEGORY_NAME = 'General';
2209
- this.DEFAULT_CATEGORY_ID = 'general';
2210
-
2211
- /* PUBLIC VARS */
2212
-
2213
- this.name = '';
2214
- this.label = '';
2215
- this.tooltip = '';
2216
- this.type = null;
2217
- this.trigger = false;
2218
- this.triggerData = null;
2219
- this.clientOnly = false;
2220
- this.editable = true;
2221
- this.attributes = null;
2222
- this.dataProvider = null;
2223
-
2224
- this.separator = null; // Parameter used to create a separator before or after the config parameter
2225
- this.defaultListItem = null; // List of sub-ConfigurationParameters, each containing the default values
2226
- this.clazz = null; // Name of the class representing the list item (not used in case of primiteve data types)
2227
- this.denyEmpty = false; // Disallow to empty a list (DataGrid config parameter type only)
2228
-
2229
- /* PRIVATE VARS */
2230
-
2231
- this._category = this.DEFAULT_CATEGORY_NAME;
2232
- this._categoryId = this.DEFAULT_CATEGORY_ID;
2233
- this._value = null;
2234
- this._initialValue = null; // Save the initial value of the configuration parameter, to check if the value was modified
2235
- this._validator = null;
2236
-
2237
- this._listItems = []; // Array of arrays of ConfigurationParameters
2238
- this._listItemsChanged = false; // Flag to be set in case a list item is added or removed
2239
- }
2240
-
2241
- //---------------------------------------------
2242
- // GETTERS / SETTERS
2243
- //---------------------------------------------
2244
-
2245
- set category(val)
2246
- {
2247
- if (val)
2248
- {
2249
- this._category = val;
2250
- this._setIdFromCategoryName(this._category);
2251
- }
2252
- }
2253
-
2254
- get category()
2255
- {
2256
- return this._category;
2257
- }
2258
-
2259
- set value(val)
2260
- {
2261
- if (this._value != val)
2262
- {
2263
- // If value is null, then we are setting this for the first time and
2264
- // we want to save the initial value, to check later if it has been modified
2265
- if (this._value == null)
2266
- this._initialValue = val;
2267
-
2268
- this._value = val;
2269
- }
2270
- }
2271
-
2272
- get value()
2273
- {
2274
- return this._value;
2275
- }
2276
-
2277
- set validator(val)
2278
- {
2279
- if (val)
2280
- this._validator = val;
2281
- }
2282
-
2283
- get validator()
2284
- {
2285
- return this._validator;
2286
- }
2287
-
2288
- /**
2289
- * An array of objects; each object contains the name-value pairs used to
2290
- * populate the list of sub-configuration parameters arrays, based on defaultListItem.
2291
- */
2292
- set listValues(arr)
2293
- {
2294
- this._setSubConfigurationParams(arr);
2295
- }
2296
-
2297
- get listValues()
2298
- {
2299
- return this._getSubConfigurationParamsValues();
2300
- }
2301
-
2302
- //---------------------------------------------
2303
- // GETTERS ONLY
2304
- //---------------------------------------------
2305
-
2306
- get isModified()
2307
- {
2308
- let _isModified = false;
2309
-
2310
- // If the parameter is used on the client only (for example in a custom trigger)
2311
- // then we never have to consider it as modified, to prevent it being sent to the server
2312
- if (!this.clientOnly)
2313
- {
2314
- if (this._value != this._initialValue || this._listItemsChanged)
2315
- _isModified = true;
2316
- else
2317
- {
2318
- // Check sub parameters
2319
- outerLoop: for (let listItem of this._listItems)
2320
- {
2321
- for (let subCP of listItem)
2322
- {
2323
- if (subCP.isModified)
2324
- {
2325
- _isModified = true;
2326
- break outerLoop;
2327
- }
2328
- }
2329
- }
2330
- }
2331
- }
2332
-
2333
- return _isModified;
2334
- }
2335
-
2336
- get categoryId()
2337
- {
2338
- return this._categoryId;
2339
- }
2340
-
2341
- get listItems()
2342
- {
2343
- return this._listItems;
2344
- }
2345
-
2346
- //---------------------------------------------
2347
- // PUBLIC METHODS
2348
- //---------------------------------------------
2349
-
2350
- /**
2351
- * Return a clone of this ConfigurationParameter.
2352
- */
2353
- clone(cloneValue = false)
2354
- {
2355
- let cp = new ConfigurationParameter();
2356
- cp.name = this.name;
2357
- cp.label = this.label;
2358
- cp.category = this.category;
2359
- cp.tooltip = this.tooltip;
2360
- cp.type = this.type;
2361
- cp.validator = this.validator;
2362
- cp.trigger = this.trigger;
2363
- cp.triggerData = (this.triggerData != null ? SFS2X.SFSArray.newFromBinaryData(this.triggerData.toBinary()) : null);
2364
- cp.clientOnly = this.clientOnly;
2365
- cp.dataProvider = this.dataProvider;
2366
-
2367
- if (cloneValue)
2368
- cp.value = this.value;
2369
-
2370
- if (this.attributes != null)
2371
- {
2372
- cp.attributes = new Object();
2373
- for (let s1 in this.attributes)
2374
- cp.attributes[s1] = this.attributes[s1];
2375
- }
2376
-
2377
- if (this.separator != null)
2378
- {
2379
- cp.separator = new Object()
2380
- for (let s2 in this.separator)
2381
- cp.separator[s2] = this.separator[s2];
2382
- }
2383
-
2384
- if (this.defaultListItem != null)
2385
- {
2386
- let clonedDefaultListItems = [];
2387
-
2388
- for (let subCP of this.defaultListItem)
2389
- clonedDefaultListItems.push(subCP.clone(cloneValue));
2390
-
2391
- cp.defaultListItem = clonedDefaultListItems;
2392
- }
2393
-
2394
- cp.listValues = this.listValues; // No need to clone this, as the listValues setter already does it
2395
- cp.clazz = this.clazz;
2396
- cp.denyEmpty = this.denyEmpty;
2397
-
2398
- return cp;
2399
- }
2400
-
2401
- /**
2402
- * Reset initial value by copying the current value.
2403
- */
2404
- resetIsModified()
2405
- {
2406
- this._initialValue = this._value;
2407
-
2408
- // Reset sub-parameters
2409
- if (this._listItems != null)
2410
- {
2411
- for (let listItem of this._listItems)
2412
- {
2413
- for (let subCP of listItem)
2414
- subCP.resetIsModified();
2415
- }
2416
- }
2417
-
2418
- this._listItemsChanged = false;
2419
- }
2420
-
2421
- addListItem(newListItem)
2422
- {
2423
- this._listItems.push(newListItem);
2424
- this._listItemsChanged = true;
2425
- }
2426
-
2427
- updateListItem(listItem, itemIndex)
2428
- {
2429
- this._listItems[itemIndex] = listItem;
2430
- this._listItemsChanged = true;
2431
- }
2432
-
2433
- removeListItem(itemIndex)
2434
- {
2435
- this._listItems.splice(itemIndex, 1);
2436
- this._listItemsChanged = true;
2437
- }
2438
-
2439
- toSfsObject()
2440
- {
2441
- let obj = new SFS2X.SFSObject();
2442
-
2443
- // Set changed setting name
2444
- obj.putUtfString('name', this.name);
2445
-
2446
- // Set changed setting class, if any
2447
- if (this.clazz != null)
2448
- obj.putUtfString('clazz', this.clazz);
2449
-
2450
- if (this.value != null)
2451
- {
2452
- // Set changed setting value
2453
- if (typeof this.value === 'boolean')
2454
- obj.putBool('value', this.value);
2455
- else if (typeof this.value === 'number')
2456
- obj.putInt('value', this.value);
2457
- else
2458
- obj.putText('value', this.value);
2459
- }
2460
- else
2461
- {
2462
- // Set changed setting list of values
2463
-
2464
- let listItems = new SFS2X.SFSArray();
2465
-
2466
- for (let a of this._listItems)
2467
- {
2468
- if (a.length == 1) // We have just one sub config param; no need to parse it complitely
2469
- {
2470
- // Simple list
2471
- let tempObj = a[0].toSfsObject();
2472
- let wa = tempObj.getWrappedItem('value');
2473
- listItems.add(wa.value, wa.type);
2474
- }
2475
- else
2476
- {
2477
- // Complex list
2478
-
2479
- let values = new SFS2X.SFSArray();
2480
-
2481
- for (let subCp of a)
2482
- values.addSFSObject(subCp.toSfsObject());
2483
-
2484
- listItems.addSFSArray(values);
2485
- }
2486
- }
2487
-
2488
- obj.putSFSArray('value', listItems);
2489
- }
2490
-
2491
- return obj;
2492
- }
2493
-
2494
- /**
2495
- * Return a description of the ConfigurationParameter instance.
2496
- */
2497
- toString()
2498
- {
2499
- let s = ``;
2500
- s += `Configuration parameter: ${this.name}\n`;
2501
- s += `\ttype: ${this.type}\n`;
2502
- s += `\tlabel: ${this.label}\n`;
2503
- s += `\tcategory name: ${this.category}\n`;
2504
- s += `\tcategory id: ${this.categoryId}\n`;
2505
- s += `\ttooltip: ${this.tooltip}\n`;
2506
- s += `\tvalue: ${this.value}\n`;
2507
- s += `\ttrigger: ${this.trigger}\n`;
2508
- s += `\ttrigger data: ${this.triggerData}\n`;
2509
- s += `\tclient only: ${this.clientOnly}\n`;
2510
- s += `\tvalidator: ${this.validator}\n`;
2511
- s += `\tis modified: ${this.isModified}\n`;
2512
-
2513
- if (this.attributes != null)
2514
- {
2515
- s += `\tcomponent attributes:\n`;
2516
-
2517
- for (let s1 in this.attributes)
2518
- s += `\t\t${s1} --> ${this.attributes[s1]}\n`;
2519
- }
2520
-
2521
- if (this.dataProvider != null)
2522
- s += `\tdata provider: ${this.dataProvider}\n`;
2523
-
2524
- if (this.separator != null)
2525
- {
2526
- s += `\tseparator:\n`;
2527
-
2528
- for (let s2 in this.separator)
2529
- s += `\t\t${s2} --> ${this.separator[s2]}\n`;
2530
- }
2531
-
2532
- if (this._listItems != null && this._listItems.length > 0)
2533
- {
2534
- s += `\t# list items: ${this._listItems.length}\n`;
2535
-
2536
- for (let i = 0; i < this._listItems.length; i++)
2537
- {
2538
- s += `\tlist item ${i} sub-parameters:\n`;
2539
- for (let e = 0; e < this._listItems[i].length; e++)
2540
- s += `\t\t${this._listItems[i][e].toCompactString()}\n`;
2541
- }
2542
-
2543
- s += `\tclass name: ${this.clazz}\n`;
2544
- s += `\tdeny empty list: ${this.denyEmpty}\n`;
2545
- }
2546
-
2547
- return s;
2548
- }
2549
-
2550
- /**
2551
- * Return a compact description of the ConfigurationParameter instance.
2552
- */
2553
- toCompactString()
2554
- {
2555
- return `Configuration parameter '${this.name}': ${this.value} ${this.isModified ? '[X]' : '[ ]'}`;
2556
- }
2557
-
2558
- //---------------------------------------------
2559
- // PRIVATE METHODS
2560
- //---------------------------------------------
2561
-
2562
- /**
2563
- * Retrieve the category id form the category name.
2564
- * Spaces and invalid characters are removed; words are separated using capitals.
2565
- */
2566
- _setIdFromCategoryName(categoryName)
2567
- {
2568
- this._categoryId = categoryName;
2569
-
2570
- // Strip invalid characters
2571
- var pattern = /[^0-9a-zA-Z]/g;
2572
- this._categoryId = this._categoryId.replace(pattern, ' ');
2573
-
2574
- // Capitalize words
2575
- var words = this._categoryId.split(' ');
2576
- this._categoryId = '';
2577
-
2578
- for (let i = 0; i < words.length; i++)
2579
- {
2580
- let word = words[i];
2581
- if (word.length > 0)
2582
- this._categoryId += (i > 0 ? word.substr(0,1).toUpperCase() : word.substr(0,1).toLowerCase()) + (word.length > 1 ? word.substr(1) : "");
2583
- }
2584
-
2585
- if (this._categoryId.length == 0)
2586
- this._categoryId = this.DEFAULT_CATEGORY_ID;
2587
- }
2588
-
2589
- _setSubConfigurationParams(_listValues)
2590
- {
2591
- this._listItems = [];
2592
-
2593
- for (let obj of _listValues)
2594
- {
2595
- let listItem = [];
2596
-
2597
- for (let defaultCP of this.defaultListItem)
2598
- {
2599
- let subCP = defaultCP.clone(false);
2600
- subCP.value = obj[subCP.name];
2601
-
2602
- listItem.push(subCP);
2603
- }
2604
-
2605
- this._listItems.push(listItem);
2606
- }
2607
- }
2608
-
2609
- _getSubConfigurationParamsValues()
2610
- {
2611
- let _listValues = [];
2612
-
2613
- for (let listItem of this._listItems)
2614
- {
2615
- let obj = {};
2616
-
2617
- for (let subCP of listItem)
2618
- {
2619
- if (subCP.value != null)
2620
- obj[subCP.name] = subCP.value;
2621
- }
2622
-
2623
- _listValues.push(obj);
2624
- }
2625
-
2626
- return _listValues;
2627
- }
2628
- }
2629
-
2630
-
2631
- /***/ })
2632
-
2633
- }]);
2634
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtMTJ+bW9kdWxlLTEzfm1vZHVsZS05LmJ1bmRsZS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1jaGVjay1ib3guanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWRyb3AtZG93bi1saXN0LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1kdWFsLWxpc3QuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWZvcm0taXRlbS5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctZ3JpZC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctbGFiZWwuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLW51bWVyaWMtc3RlcHBlci5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctdGV4dC1pbnB1dC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctdmVjdG9yLTNkLmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL3dpZGdldHMvbGlzdC1pdGVtLWVkaXRvci5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci93aWRnZXRzL3ZlY3Rvci0zZC1pbnB1dC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy91dGlscy91aWJ1aWxkZXIvY29uZmlnLWZvcm0taXRlbS1mYWN0b3J5LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL3V0aWxzL3VpYnVpbGRlci9jb25maWctaW50ZXJmYWNlLWJ1aWxkZXIuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvdXRpbHMvdWlidWlsZGVyL2NvbmZpZ3VyYXRpb24tcGFyYW1ldGVyLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Q29uZmlnRm9ybUl0ZW19IGZyb20gJy4vY29uZmlnLWZvcm0taXRlbSc7XG5pbXBvcnQge0NvbmZpZ0xhYmVsfSBmcm9tICcuL2NvbmZpZy1sYWJlbCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdDaGVja0JveCBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIGEgc2ltcGxlIGxhYmVsIGlzIHVzZWQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0XHRsZXQgY29uZmlnID0ge1xuXHRcdFx0XHR0eXBlOiAnY2hlY2tib3gnLFxuXHRcdFx0XHRjbGFzczogJycsXG5cdFx0XHRcdGlkOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdG5hbWU6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdFx0J2RhdGEtcm9sZSc6ICdzd2l0Y2gnLFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0QXR0cmlidXRlcyhjb25maWcpO1xuXG5cdFx0XHQvLyBTZXQgYWRkaXRpb25hbCB3aWRnZXQgYXR0cmlidXRlcyBiYXNlZCBvbiB2YWxpZGF0aW9uIHJ1bGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gQ3JlYXRlIHdpZGdldCdzIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSAkKCc8aW5wdXQ+JywgY29uZmlnKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBDb25maWdMYWJlbCgpO1xuXG5cdFx0Ly8gUmV0dXJuIGNvbXBvbmVudFxuXHRcdHJldHVybiB0aGlzLl93aWRnZXRIdG1sO1xuXHR9XG5cblx0LyoqXG5cdCAqIEluaXRpYWxpemUgd2lkZ2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG4gICBfaW5pdGlhbGl6ZSgpXG4gICB7XG5cdCAgIGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHQgICB7XG5cdFx0ICAgLy8gSW5pdGlhbGl6ZSBrZW5kbyB3aWRnZXRcblx0XHQgICBrZW5kby5pbml0KHRoaXMuX3dpZGdldEh0bWwpO1xuXG5cdFx0ICAgLy8gU2F2ZSByZWYuIHRvIHdpZGdldFxuXHRcdCAgIHRoaXMuX2lubmVyV2lkZ2V0ID0gdGhpcy5fd2lkZ2V0SHRtbC5kYXRhKCdrZW5kb1N3aXRjaCcpO1xuXG5cdFx0ICAgLy8gRW5hYmxlIHZhbHVlIGNvbW1pdCBiaW5kaW5nXG5cdFx0ICAgdGhpcy5faW5uZXJXaWRnZXQuYmluZCgnY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0ICAgfVxuXG5cdCAgIC8vIFByb2NlZWQgd2l0aCBpbml0aWFsaXphdGlvblxuXHQgICBzdXBlci5faW5pdGlhbGl6ZSgpO1xuICAgfVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIHRoZSBsYWJlbCB0ZXh0IGlzIHNldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC52YWx1ZSh0aGlzLl9kYXRhLnZhbHVlKTtcblx0XHRlbHNlXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLnZhbHVlID0gdGhpcy5fZGF0YS52YWx1ZTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgZGlzYWJsZWQgc3RhdGUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldEVkaXRFbmFibGVkKClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdFx0dGhpcy5faW5uZXJXaWRnZXQuZW5hYmxlKHRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl9pbm5lcldpZGdldC52YWx1ZSgpO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnY29uZmlnLWNoZWNrLWJveCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctY2hlY2stYm94JywgQ29uZmlnQ2hlY2tCb3gpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0Ryb3BEb3duTGlzdCBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIGEgc2ltcGxlIGxhYmVsIGlzIHVzZWQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0XHRsZXQgY29uZmlnID0ge1xuXHRcdFx0XHRjbGFzczogJ2Zvcm0tY29udHJvbCcsXG5cdFx0XHRcdGlkOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdG5hbWU6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdFx0J2RhdGEtcm9sZSc6ICdkcm9wZG93bmxpc3QnLFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0QXR0cmlidXRlcyhjb25maWcpO1xuXG5cdFx0XHQvLyBTZXQgYWRkaXRpb25hbCB3aWRnZXQgYXR0cmlidXRlcyBiYXNlZCBvbiB2YWxpZGF0aW9uIHJ1bGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gQ3JlYXRlIHdpZGdldCdzIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSAkKCc8aW5wdXQ+JywgY29uZmlnKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBDb25maWdMYWJlbCgpO1xuXG5cdFx0Ly8gUmV0dXJuIGNvbXBvbmVudFxuXHRcdHJldHVybiB0aGlzLl93aWRnZXRIdG1sO1xuXHR9XG5cblx0LyoqXG5cdCAqIEluaXRpYWxpemUgd2lkZ2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG4gICBfaW5pdGlhbGl6ZSgpXG4gICB7XG5cdCAgIGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHQgICB7XG5cdFx0ICAgLy8gSW5pdGlhbGl6ZSBrZW5kbyB3aWRnZXRcblx0XHQgICBrZW5kby5pbml0KHRoaXMuX3dpZGdldEh0bWwpO1xuXG5cdFx0ICAgLy8gU2F2ZSByZWYuIHRvIHdpZGdldFxuXHRcdCAgIHRoaXMuX2lubmVyV2lkZ2V0ID0gdGhpcy5fd2lkZ2V0SHRtbC5kYXRhKCdrZW5kb0Ryb3BEb3duTGlzdCcpO1xuXG5cdFx0ICAgLy8gU2V0IGxpc3QgaXRlbXNcblx0XHQgICB0aGlzLl9pbm5lcldpZGdldC5zZXREYXRhU291cmNlKHRoaXMuX2dldERhdGFTb3VyY2UodGhpcy5fZGF0YS5kYXRhUHJvdmlkZXIpKVxuXG5cdFx0ICAgLy8gRW5hYmxlIHZhbHVlIGNvbW1pdCBiaW5kaW5nXG5cdFx0ICAgdGhpcy5fd2lkZ2V0SHRtbC5iaW5kKCdjaGFuZ2UnLCAkLnByb3h5KHRoaXMuX29uVmFsdWVJbnB1dCwgdGhpcykpO1xuXHQgICB9XG5cblx0ICAgLy8gUHJvY2VlZCB3aXRoIGluaXRpYWxpemF0aW9uXG5cdCAgIHN1cGVyLl9pbml0aWFsaXplKCk7XG4gICB9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgdGhlIGxhYmVsIHRleHQgaXMgc2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRWYWx1ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX2lubmVyV2lkZ2V0LnZhbHVlKHRoaXMuX2RhdGEudmFsdWUpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsdWUgPSB0aGlzLl9kYXRhLnZhbHVlO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC53cmFwcGVyLmF0dHIoJ2Rpc2FibGVkJywgIXRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl9pbm5lcldpZGdldC52YWx1ZSgpO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0X2dldERhdGFTb3VyY2UoZHBTdHJpbmcpXG5cdHtcblx0XHRpZiAoZHBTdHJpbmcpXG5cdFx0XHRyZXR1cm4gZHBTdHJpbmcuc3BsaXQoJywnKTtcblxuXHRcdC8vIEluIGNhc2UgdGhlIGRhdGFwcm92aWRlciBpcyBlbXB0eSwgYWRkIGF0IGxlYXN0IHRoZSBjdXJyZW50IHZhbHVlXG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIFt0aGlzLl9kYXRhLnZhbHVlXTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1kcm9wLWRvd24tbGlzdCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctZHJvcC1kb3duLWxpc3QnLCBDb25maWdEcm9wRG93bkxpc3QpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0R1YWxMaXN0IGV4dGVuZHMgQ29uZmlnRm9ybUl0ZW1cbntcblx0Y29uc3RydWN0b3IoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZylcblx0e1xuXHQgICAgc3VwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlIHdpZGdldCB0byByZW5kZXIgdGhlIENvbmZpZ1BhcmFtZXRlci5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGRpdj4nKTtcblxuXHRcdGNvbnN0IGF2YWlsYWJsZUlkID0gdGhpcy5fZ2V0SWQodGhpcy5fZGF0YS5uYW1lLCAnYXZhaWxhYmxlJyk7XG5cdFx0Y29uc3Qgc2VsZWN0ZWRJZCA9IHRoaXMuX2dldElkKHRoaXMuX2RhdGEubmFtZSwgJ3NlbGVjdGVkJyk7XG5cblx0XHQvLyBDcmVhdGUgaGVhZGVyIGZvciBsYWJlbHNcblx0XHRsZXQgaGVhZGVyID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICdmb3JtLWxhYmVsLWNvbnRhaW5lciBkdWFsLWxpc3QtbGFiZWxzJ30pO1xuXG5cdFx0aGVhZGVyLmFwcGVuZCgkKCc8bGFiZWw+Jywge1xuXHRcdFx0Y2xhc3M6ICdmb250LWl0YWxpYyBmb3JtLWxhYmVsIGR1YWwtbGlzdC1sZWZ0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHRcdGZvcjogYXZhaWxhYmxlSWQsXG5cdFx0fSkudGV4dCgnQXZhaWxhYmxlJykpO1xuXG5cdFx0aGVhZGVyLmFwcGVuZCgkKCc8bGFiZWw+Jywge1xuXHRcdFx0Y2xhc3M6ICdmb250LWl0YWxpYyBmb250LXdlaWdodC1ib2xkIGZvcm0tbGFiZWwgZHVhbC1saXN0LXJpZ2h0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHRcdGZvcjogc2VsZWN0ZWRJZCxcblx0XHR9KS50ZXh0KCdTZWxlY3RlZCcpKTtcblxuXHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKGhlYWRlcik7XG5cblx0XHQvLyBBZGQgYXZhaWxhYmxlIGl0ZW1zIGxpc3Rcblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0SHRtbCA9ICQoJzxzZWxlY3Q+Jywge1xuXHRcdFx0aWQ6IGF2YWlsYWJsZUlkLFxuXHRcdFx0Y2xhc3M6ICdkdWFsLWxpc3QtbGVmdC1jb2wnICsgKCF0aGlzLl9kYXRhLmVkaXRhYmxlID8gJyBuby1pbnRlcmFjdCcgOiAnJyksXG5cdFx0fSk7XG5cdFx0dGhpcy5fd2lkZ2V0SHRtbC5hcHBlbmQodGhpcy5fYXZhaWxhYmxlTGlzdEh0bWwpO1xuXG5cdFx0Ly8gQWRkIHNlbGVjdGVkIGl0ZW1zIGxpc3Rcblx0XHR0aGlzLl9zZWxlY3RlZExpc3RIdG1sID0gJCgnPHNlbGVjdD4nLCB7XG5cdFx0XHRpZDogc2VsZWN0ZWRJZCxcblx0XHRcdGNsYXNzOiAnZHVhbC1saXN0LXJpZ2h0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHR9KTtcblx0XHR0aGlzLl93aWRnZXRIdG1sLmFwcGVuZCh0aGlzLl9zZWxlY3RlZExpc3RIdG1sKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8vIElEcyBjb250YWluaW5nIGEgXCIuXCIgY2F1c2UgaXNzdWVzIHRvIGNvbm5lY3RlZCBsaXN0c1xuXHRfZ2V0SWQobmFtZSwgc3VmZml4KVxuXHR7XG5cdFx0cmV0dXJuIG5hbWUucmVwbGFjZSgnLicsICdfJykgKyAnLScgKyBzdWZmaXg7XG5cdH1cblxuXHQvKipcblx0ICogSW5pdGlhbGl6ZSB3aWRnZXQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2luaXRpYWxpemUoKVxuXHR7XG5cdFx0Ly8gSW5pdGlhbGl6ZSBcImF2YWxhYmxlXCIgbGlzdGJveFxuXHRcdHRoaXMuX2F2YWlsYWJsZUxpc3QgPSB0aGlzLl9hdmFpbGFibGVMaXN0SHRtbC5rZW5kb0xpc3RCb3goe1xuICAgICAgICAgICAgY29ubmVjdFdpdGg6IHRoaXMuX2dldElkKHRoaXMuX2RhdGEubmFtZSwgJ3NlbGVjdGVkJyksXG4gICAgICAgICAgICB0b29sYmFyOiB7XG4gICAgICAgICAgICAgICAgdG9vbHM6IHRoaXMuX2RhdGEuZWRpdGFibGUgPyBbJ3RyYW5zZmVyVG8nLCAndHJhbnNmZXJGcm9tJywgJ3RyYW5zZmVyQWxsVG8nLCAndHJhbnNmZXJBbGxGcm9tJ10gOiBbXVxuICAgICAgICAgICAgfSxcblx0XHRcdHRlbXBsYXRlOiBcIjxkaXY+Izp2YWx1ZSM8L2Rpdj5cIixcblx0XHRcdHNlbGVjdGFibGU6ICdtdWx0aXBsZScsXG4gICAgICAgIH0pLmRhdGEoJ2tlbmRvTGlzdEJveCcpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBcInNlbGVjdGVkXCIgbGlzdGJveFxuICAgICAgICB0aGlzLl9zZWxlY3RlZExpc3QgPSB0aGlzLl9zZWxlY3RlZExpc3RIdG1sLmtlbmRvTGlzdEJveCh7XG5cdFx0XHR0ZW1wbGF0ZTogXCI8ZGl2PiM6dmFsdWUjPC9kaXY+XCIsXG5cdFx0XHRzZWxlY3RhYmxlOiAnbXVsdGlwbGUnLFxuXHRcdFx0Ly8gVGhlIGZvbGxvd2luZyBsaXN0ZW5lcnMgY2FuJ3QgYmUgdXNlZCBiZWNhdXNlIGV2ZW50cyBhcmUgZmlyZWQgYmVmb3JlIHRoZSBkYXRhc291cmNlIGlzIGFjdHVhbGx5IHVwZGF0ZWRcblx0XHRcdC8vIFdlIGhhdmUgdG8gdXNlIGEgY2hhbmdlIGV2ZW50IGxpc3RlbmVyIG9uIHRoZSBkYXRhc291cmNlIChzZWUgYmVsb3cpLCBldmVuIGlmIG5vdCBvcHRpbWFsXG5cdFx0XHQvL2FkZDogJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpLFxuXHRcdFx0Ly9yZW1vdmU6ICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKSxcblx0XHR9KS5kYXRhKCdrZW5kb0xpc3RCb3gnKTtcblxuXHRcdC8vIFByb2NlZWQgd2l0aCBpbml0aWFsaXphdGlvblxuXHRcdHN1cGVyLl9pbml0aWFsaXplKCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRhdGFzb3VyY2UuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldFZhbHVlKClcblx0e1xuXHRcdGxldCBhdmFpbGFibGVBcnIgPSB0aGlzLl9kYXRhLmRhdGFQcm92aWRlciAhPSAnJyA/IHRoaXMuX2RhdGEuZGF0YVByb3ZpZGVyLnNwbGl0KCcsJykgOiBbXTtcblx0XHRsZXQgc2VsZWN0ZWRBcnIgPSB0aGlzLl9kYXRhLnZhbHVlICE9ICcnID8gdGhpcy5fZGF0YS52YWx1ZS5zcGxpdCgnLCcpIDogW107XG5cblx0XHQvLyBSZW1vdmUgc2VsZWN0ZWQgdmFsdWVzIGZyb20gYXZhaWxhYmxlIHZhbHVlc1xuXHRcdGlmIChzZWxlY3RlZEFyci5sZW5ndGggPiAwKVxuXHRcdHtcblx0XHRcdGxldCB0ZW1wID0gW107XG5cblx0XHRcdGZvciAobGV0IHZhbCBvZiBhdmFpbGFibGVBcnIpXG5cdFx0XHR7XG5cdFx0XHRcdGlmIChzZWxlY3RlZEFyci5pbmRleE9mKHZhbCkgPT0gLTEpXG5cdFx0XHRcdFx0dGVtcC5wdXNoKHZhbCk7XG5cdFx0XHR9XG5cblx0XHRcdGF2YWlsYWJsZUFyciA9IHRlbXA7XG5cdFx0fVxuXG5cdFx0Ly8gQ29udmVydCBsaXN0cyBvZiBzdHJpbmdzIHRvIGxpc3RzIG9mIG9iamVjdHNcblx0XHRsZXQgYXZhaWxhYmxlVmFsdWVzID0gW107XG5cdFx0Zm9yIChsZXQgdmFsIG9mIGF2YWlsYWJsZUFycilcblx0XHRcdGF2YWlsYWJsZVZhbHVlcy5wdXNoKHt2YWx1ZTogdmFsfSk7XG5cblx0XHRsZXQgc2VsZWN0ZWRWYWx1ZXMgPSBbXTtcblx0XHRmb3IgKGxldCB2YWwgb2Ygc2VsZWN0ZWRBcnIpXG5cdFx0XHRzZWxlY3RlZFZhbHVlcy5wdXNoKHt2YWx1ZTogdmFsfSk7XG5cblx0XHQvLyBDbGVhciBzZWxlY3Rpb25cblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cdFx0dGhpcy5fc2VsZWN0ZWRMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cblx0XHQvLyBTZXQgZGF0YXNvdXJjZXNcblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LnNldERhdGFTb3VyY2UobmV3IGtlbmRvLmRhdGEuRGF0YVNvdXJjZSh7XG5cdFx0XHRkYXRhOiBhdmFpbGFibGVWYWx1ZXNcblx0XHR9KSk7XG5cblx0XHR0aGlzLl9zZWxlY3RlZExpc3Quc2V0RGF0YVNvdXJjZShuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKHtcblx0XHRcdGRhdGE6IHNlbGVjdGVkVmFsdWVzLFxuXHRcdFx0Ly8gV2UgbGlzdGVuIHRvIHRoZSBjaGFuZ2UgZXZlbnQgaW5zdGVhZCBvZiB0aGUgYWRkL3JlbW92ZSBldmVudHMgb24gdGhlIGxpc3Rib3gsIGJlY2F1c2UgdGhvc2UgYXJlIGZpcmVkIGJlZm9yZSB0aGUgZGF0YXNvdXJjZSBpcyB1cGRhdGVkXG5cdFx0XHQvLyBUaGlzIGlzIG5vdCBvcHRpbWFsIGJlY2F1c2UgdGhlIGV2ZW50IGlzIGZpcmVkIGZvciBlYWNoIGl0ZW0gYWRkZWQgdG8gb3IgcmVtb3ZlZCBmcm9tIHRoZSBkYXRhc291cmNlXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKVxuXHRcdH0pKTtcblxuXHRcdC8vIERpc2FibGUgZWRpdGluZ1xuXHRcdGlmICghdGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmVuYWJsZSgnLmstaXRlbScsIGZhbHNlKTtcblx0XHRcdHRoaXMuX3NlbGVjdGVkTGlzdC5lbmFibGUoJy5rLWl0ZW0nLCBmYWxzZSk7XG5cdFx0fVxuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gQ2xlYXIgc2VsZWN0aW9uXG5cdFx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZExpc3QuY2xlYXJTZWxlY3Rpb24oKTtcblxuXHRcdFx0Ly8gRW5hYmxlL2Rpc2FibGUgbGlzdHNcblx0XHRcdHRoaXMuX2F2YWlsYWJsZUxpc3Qud3JhcHBlci5hdHRyKCdkaXNhYmxlZCcsICF0aGlzLl9lZGl0RW5hYmxlZCk7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZExpc3Qud3JhcHBlci5hdHRyKCdkaXNhYmxlZCcsICF0aGlzLl9lZGl0RW5hYmxlZCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB2YWx1ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfb25WYWx1ZUlucHV0KGUpXG5cdHtcblx0XHRsZXQgbGlzdERhdGEgPSB0aGlzLl9zZWxlY3RlZExpc3QuZGF0YVNvdXJjZS5kYXRhKCk7XG5cblx0XHQvLyBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdG8gbmV3IHZhbHVlXG5cdFx0dGhpcy5fZGF0YS52YWx1ZSA9IGxpc3REYXRhLm1hcChlID0+IGUudmFsdWUpLmpvaW4oJywnKTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1kdWFsLWxpc3QnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLWR1YWwtbGlzdCcsIENvbmZpZ0R1YWxMaXN0KTtcbiIsImV4cG9ydCBjbGFzcyBDb25maWdGb3JtSXRlbSBleHRlbmRzIEhUTUxFbGVtZW50XG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKCk7XG5cblx0XHR0aGlzLmlkID0gJ2Zvcm0taXRlbS0nICsgY29uZmlnUGFyYW0ubmFtZTtcblx0XHR0aGlzLl9lZGl0RW5hYmxlZCA9IGVkaXRFbmFibGVkO1xuXHRcdHRoaXMuX2RhdGEgPSBjb25maWdQYXJhbTtcblxuXHRcdC8vIENyZWF0ZSBmb3JtIGl0ZW0gdmlld1xuXHRcdHRoaXMuX2J1aWxkVmlldyhpbkRpYWxvZyk7XG5cblx0XHQvLyBJbml0aWFsaXplIGZvcm0gaXRlbVxuXHRcdHRoaXMuX2luaXRpYWxpemUoKTtcblx0fVxuXG5cdGNvbm5lY3RlZENhbGxiYWNrKClcblx0e1xuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHQvLyBOT1RFOiB3aGVuIGEgQ29uZmlnRm9ybUl0ZW0gaXMgaW5zdGFudGlhdGVkLCB0aGUgX3RyaWdnZXJFdmVudCBtZXRob2QgaXMgY2FsbGVkIGFzIHNvb24gYXMgaXRzIHZhbHVlIGlzIHNldC5cblx0XHQvLyBXaGVuIHRoaXMgaGFwcGVuc28sIGR1ZSB0byB0aGUgZmFjdCB0aGF0IHRoZSBvYmplY3QgaXMgbm90IHlldCBpbiB0aGUgRE9NLCB0aGUgZXZlbnQgaXMgbm90IGNhdGNoZWQgYnkgdGhlIGxpc3RlbmVyXG5cdFx0Ly8gKHdoaWNoIGlzIGF0dGFjaGVkIHRvIHRoZSBvdXRlciBjb250YWluZXIpLiBTbyBmb3JjaW5nIHRoZSBldmVudCB0byB0cmlnZ2VyIGFnYWluIGFzIHNvb24gYXMgdGhlIENvbmZpZ0Zvcm1JdGVtXG5cdFx0Ly8gaXMgYXBwZW5kZWQgdG8gdGhlIERPTSBpcyBuZWVkZWQuXG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cblxuXHRzZXQgZGF0YShjb25maWdQYXJhbSlcblx0e1xuXHRcdHRoaXMuX2RhdGEgPSBjb25maWdQYXJhbTtcblx0XHR0aGlzLl9zZXRXaWRnZXRWYWx1ZSgpO1xuXHR9XG5cblx0Z2V0IGRhdGEoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2RhdGE7XG5cdH1cblxuXHRzZXQgZWRpdEVuYWJsZWQoZW5hYmxlKVxuXHR7XG5cdFx0aWYgKGVuYWJsZSAhPSB0aGlzLl9lZGl0RW5hYmxlZClcblx0XHR7XG5cdFx0XHR0aGlzLl9lZGl0RW5hYmxlZCA9IGVuYWJsZTtcblx0XHRcdHRoaXMuX3NldFdpZGdldEVkaXRFbmFibGVkKCk7XG5cdFx0fVxuXHR9XG5cblx0Z2V0IGVkaXRFbmFibGVkKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9lZGl0RW5hYmxlZDtcblx0fVxuXG5cdF9idWlsZFZpZXcoaXNJbnNpZGVEaWFsb2cpXG5cdHtcblx0XHRpZiAoIWlzSW5zaWRlRGlhbG9nKVxuXHRcdHtcblx0XHRcdC8vIFNldCBhZGRpdGlvbmFsIGNsYXNzZXMgZm9yIGlubmVyIHdpZGdldFxuXHRcdFx0bGV0IGNsYXNzTmFtZXMgPSAnJztcblxuXHRcdFx0c3dpdGNoICh0aGlzLl9kYXRhLnR5cGUpXG5cdFx0XHR7XG5cdFx0XHRcdGNhc2UgJ0R1YWxMaXN0Jzpcblx0XHRcdFx0XHRjbGFzc05hbWVzID0gJ2NvbC1zbS03IGNvbC1sZy04Jztcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAnRGF0YUdyaWQnOlxuXHRcdFx0XHRcdGNsYXNzTmFtZXMgPSAnY29sLXNtJzsgLy8gVXNlICdjb2wtc20tNyBjb2wtbGctOCcgZm9yIERhdGFHcmlkIHRvbz9cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRjbGFzc05hbWVzID0gJ2NvbC1zbS1hdXRvJztcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBHZW5lcmF0ZSBib2lsZXJwbGF0ZSBodG1sLCBzdXJyb3VuZGluZyB0aGUgYWN0dWFsIHdpZGdldCAobGFiZWwsIG51bWVyaWMgc3RlcHBlciwgZXRjKVxuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSBgXG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwIHBvc2l0aW9uLXJlbGF0aXZlIHJvd1wiPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNSBjb2wtbGctNCBjb2wtZm9ybS1sYWJlbCBmb3JtLWxhYmVsLWNvbnRhaW5lclwiPlxuXHRcdFx0XHRcdFx0PGxhYmVsIGZvcj1cIiR7dGhpcy5fZGF0YS5uYW1lfVwiIGNsYXNzPVwiZm9ybS1sYWJlbCAkeyh0aGlzLl9kYXRhLmNsaWVudE9ubHkgPyAnY2xpZW50LW9ubHknIDogJycpfVwiPiR7dGhpcy5fZGF0YS5sYWJlbH0gPGkgY2xhc3M9XCJmYXMgZmEtcXVlc3Rpb24tY2lyY2xlIHRleHQtbXV0ZWQgaGVscFwiIHRpdGxlPVwiJHt0aGlzLl9kYXRhLnRvb2x0aXB9XCI+PC9pPjwvbGFiZWw+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cImlubmVyLXdpZGdldCBhbGlnbi1zZWxmLWNlbnRlciAke2NsYXNzTmFtZXN9XCI+XG5cdFx0XHRcdFx0XHQ8c3BhbiBjbGFzcz1cImstaW52YWxpZC1tc2dcIiBkYXRhLWZvcj1cIiR7dGhpcy5fZGF0YS5uYW1lfVwiPjwvc3Bhbj5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PC9kaXY+XG5cdFx0XHRgO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSBgXG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwIHBvc2l0aW9uLXJlbGF0aXZlXCI+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cImNvbC1mb3JtLWxhYmVsIGZvcm0tbGFiZWwtY29udGFpbmVyXCI+XG5cdFx0XHRcdFx0XHQ8bGFiZWwgZm9yPVwiJHt0aGlzLl9kYXRhLm5hbWV9XCIgY2xhc3M9XCJmb3JtLWxhYmVsICR7KHRoaXMuX2RhdGEuY2xpZW50T25seSA/ICdjbGllbnQtb25seScgOiAnJyl9XCI+JHt0aGlzLl9kYXRhLmxhYmVsfSA8aSBjbGFzcz1cImZhcyBmYS1xdWVzdGlvbi1jaXJjbGUgdGV4dC1tdXRlZCBoZWxwXCIgdGl0bGU9XCIke3RoaXMuX2RhdGEudG9vbHRpcH1cIj48L2k+PC9sYWJlbD5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiaW5uZXItd2lkZ2V0XCI+XG5cdFx0XHRcdFx0XHQ8c3BhbiBjbGFzcz1cImstaW52YWxpZC1tc2dcIiBkYXRhLWZvcj1cIiR7dGhpcy5fZGF0YS5uYW1lfVwiPjwvc3Bhbj5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PC9kaXY+XG5cdFx0XHRgO1xuXHRcdH1cblxuXHRcdC8vIENyZWF0ZSBpbm5lciB3aWRnZXQgKG11c3QgYmUgb3ZlcnJpZGRlbilcblx0XHRsZXQgd2lkZ2V0ID0gdGhpcy5fZ2VuZXJhdGVJbm5lcldpZGdldCgpO1xuXG5cdFx0Ly8gQXBwZW5kIGlubmVyIHdpZGdldFxuXHRcdCQodGhpcykuZmluZCgnLmlubmVyLXdpZGdldCcpLnByZXBlbmQod2lkZ2V0KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBUTyBCRSBPVkVSUklEREVOXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHQvLyBTaG93IGFuIGVycm9yLCBzaG91bGQgYmUgb3ZlcnJpZGRlblxuXHRcdGNvbnNvbGUuZXJyb3IoYFVuYWJsZSB0byBjcmVhdGUgJHt0aGlzLl9kYXRhLnR5cGV9IGZvcm0gaXRlbSBmb3IgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXIgJHt0aGlzLmlkfWApO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCBhdHRyaWJ1dGVzIG9uIHRoZSB3aWRnZXQgY29uZmlndXJhdGlvbiBvYmplY3QuXG5cdCAqL1xuXHRfc2V0V2lkZ2V0QXR0cmlidXRlcyhjb25maWcpXG5cdHtcblx0XHRjb25zdCBhdHRyaWJzID0gdGhpcy5fZGF0YS5hdHRyaWJ1dGVzO1xuXG5cdFx0aWYgKGF0dHJpYnMpXG5cdFx0e1xuXHRcdFx0Zm9yIChsZXQgYXR0ciBpbiBhdHRyaWJzKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25maWdbYXR0cl0gPSBhdHRyaWJzW2F0dHJdO1xuXG5cdFx0XHRcdGlmIChhdHRyID09ICdwYXR0ZXJuJylcblx0XHRcdFx0XHRjb25maWdbJ2RhdGEtcGF0dGVybi1tc2cnXSA9ICdDb250YWlucyBpbnZhbGlkIGNoYXJhY3RlcnMnO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgYWRkaXRpb25hbCBhdHRyaWJ1dGVzIG9uIHRoZSB3aWRnZXQgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gcHJvcGVybHkgdmFsaWRhdGUgaW5wdXQuXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoY29uZmlnKVxuXHR7XG5cdFx0Y29uc3QgdmFsID0gdGhpcy5fZGF0YS52YWxpZGF0b3I7XG5cblx0XHRpZiAodmFsICE9IG51bGwgJiYgdmFsICE9ICcnKVxuXHRcdHtcblx0XHRcdGlmICh2YWwgPT0gJ2lwJylcblx0XHRcdHtcblx0XHRcdFx0Y29uZmlnWydwYXR0ZXJuJ10gPSAnXigyNVswLTVdfDJbMC00XVswLTldfFswMV0/WzAtOV1bMC05XT8pXFwuKDI1WzAtNV18MlswLTRdWzAtOV18WzAxXT9bMC05XVswLTldPylcXC4oMjVbMC01XXwyWzAtNF1bMC05XXxbMDFdP1swLTldWzAtOV0/KVxcLigyNVswLTVdfDJbMC00XVswLTldfFswMV0/WzAtOV1bMC05XT8pJCc7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1wYXR0ZXJuLW1zZyddID0gJ0ludmFsaWQgSVAgYWRkcmVzcyc7XG5cdFx0XHRcdGNvbmZpZ1sncmVxdWlyZWQnXSA9IHRydWU7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1yZXF1aXJlZC1tc2cnXSA9ICdSZXF1aXJlZCc7XG5cdFx0XHR9XG5cblx0XHRcdGVsc2UgaWYgKHZhbCA9PSAnbm90TnVsbCcpXG5cdFx0XHR7XG5cdFx0XHRcdGNvbmZpZ1sncmVxdWlyZWQnXSA9IHRydWU7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1yZXF1aXJlZC1tc2cnXSA9ICdSZXF1aXJlZCc7XG5cdFx0XHR9XG5cblx0XHRcdGVsc2UgaWYgKHZhbCA9PSAncHdkJylcblx0XHRcdHtcblx0XHRcdFx0Y29uZmlnWydwYXR0ZXJuJ10gPSAnXi57Nix9JCc7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1wYXR0ZXJuLW1zZyddID0gJ01pbmltdW0gbGVuZ3RoOiA2IGNoYXJhY3RlcnMnO1xuXHRcdFx0fVxuXG5cdFx0XHRlbHNlIGlmICh2YWwgPT0gJ3Bvc051bScpXG5cdFx0XHR7XG5cdFx0XHRcdGNvbmZpZ1sncGF0dGVybiddID0gJ15bMC05XVxcZCokJztcblx0XHRcdFx0Y29uZmlnWydkYXRhLXBhdHRlcm4tbXNnJ10gPSAnTm9uLW5lZ2F0aXZlIG51bWJlciByZXF1aXJlZCc7XG5cdFx0XHR9XG5cblx0XHRcdGVsc2UgaWYgKHZhbCA9PSAnYW9pJylcblx0XHRcdHtcblx0XHRcdFx0Ly8gTm90aGluZyB0byBkb1xuXHRcdFx0XHQvLyBTZWUgS2VuZG8gdmFsaWRhdGlvbiBpbml0aWFsaXphdGlvbiBpbiBjb25maWctaW50ZXJmYWNlLWJ1aWxkZXIuanNcblx0XHRcdH1cblxuXHRcdFx0ZWxzZSBpZiAodmFsID09ICd1cmwnKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25maWdbJ3R5cGUnXSA9ICd1cmwnO1xuXHRcdFx0XHRjb25maWdbJ2RhdGEtdXJsLW1zZyddID0gJ0ludmFsaWQgVVJMJztcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogSW5pdGlhbGl6ZSBmb3JtIGl0ZW0uXG5cdCAqXG5cdCAqIE5PVEU6IG11c3QgYmUgb3ZlcnJpZGRlbiBpZiBpbm5lciB3aWRnZXQgcmVxdWlyZXMgc3BlY2lhbCBpbml0aWFsaXphdGlvbiAoZm9yIGV4YW1wbGUgS2VuZG8gd2lkZ2V0cylcblx0ICovXG5cdF9pbml0aWFsaXplKClcblx0e1xuXHRcdC8vIFNldCB2YWx1ZVxuIFx0ICAgdGhpcy5fc2V0V2lkZ2V0VmFsdWUoKTtcblxuIFx0ICAgLy8gU2V0IGVkaXQgZW5hYmxlZFxuIFx0ICAgdGhpcy5fc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBUTyBCRSBPVkVSUklEREVOXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0Ly8gTm90aGluZyB0byBkbywgbXVzdCBiZSBvdmVycmlkZGVuXG5cdH1cblxuXHQvKipcblx0ICogVE8gQkUgT1ZFUlJJRERFTlxuXHQgKi9cblx0X3NldFdpZGdldEVkaXRFbmFibGVkKClcblx0e1xuXHRcdC8vIE5vdGhpbmcgdG8gZG8sIG11c3QgYmUgb3ZlcnJpZGRlblxuXHR9XG5cblx0LyoqXG5cdCAqIFRPIEJFIE9WRVJSSURERU5cblx0ICovXG5cdF9vblZhbHVlSW5wdXQoZSlcblx0e1xuXHRcdC8vIE5vdGhpbmcgdG8gZG8sIG11c3QgYmUgb3ZlcnJpZGRlblxuXHR9XG5cblx0X3RyaWdnZXJFdmVudCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS50cmlnZ2VyKVxuXHRcdHtcblx0XHRcdGxldCBldmVudCA9IG5ldyBDdXN0b21FdmVudCgndmFsdWUtc2V0Jywge2RldGFpbDogbnVsbCwgYnViYmxlczogdHJ1ZSwgY2FuY2VsYWJsZTogdHJ1ZX0pO1xuXHRcdFx0dGhpcy5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcblx0XHR9XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdjb25maWctZm9ybS1pdGVtJykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2NvbmZpZy1mb3JtLWl0ZW0nLCBDb25maWdGb3JtSXRlbSk7XG4iLCJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuaW1wb3J0IHtMaXN0SXRlbUVkaXRvcn0gZnJvbSAnLi93aWRnZXRzL2xpc3QtaXRlbS1lZGl0b3InO1xuXG5leHBvcnQgY2xhc3MgQ29uZmlnR3JpZCBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0Ly8gQ3JlYXRlIG1haW4gd2lkZ2V0J3MgaHRtbFxuXHRcdHRoaXMuX3dpZGdldEh0bWwgPSAkKCc8ZGl2PicsIHtjbGFzczogJyd9KTtcblxuXHRcdC8vIFNldCBncmlkIHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0bGV0IGdyaWRDb25maWcgPSB7XG5cdFx0XHRpZDogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0bmFtZTogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0Y2xhc3M6ICdsaW1pdGVkLWhlaWdodCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKVxuXHRcdH07XG5cblx0XHQvLyBBcHBlbmQgZ3JpZCB0byBtYWluIGh0bWw7IGdyaWQgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gS2VuZG8gd2lkZ2V0IGR1cmluZyBpbml0aWFsaXphdGlvblxuXHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKCQoJzxkaXY+JywgZ3JpZENvbmZpZykpO1xuXG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gQlVUVE9OU1xuXG5cdFx0XHQvLyBDcmVhdGUgYnV0dG9ucyBjb250YWluZXJcblx0XHRcdGxldCBidXR0b25zID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICdtdC0yIHRleHQtcmlnaHQnfSk7XG5cblx0XHRcdC8vIEFwcGVuZCBidXR0b25zIHRvIGNvbnRhaW5lclxuXHRcdFx0dGhpcy5fYWRkQnV0dG9uID0gJCgnPGJ1dHRvbj4nLCB7dHlwZTogJ2J1dHRvbicsIGNsYXNzOiAnay1idXR0b24gay1zZWNvbmRhcnknLCB0aXRsZTogJ0FkZCd9KS5hcHBlbmQoJCgnPGkgY2xhc3M9XCJmYXMgZmEtcGx1c1wiPjwvaT4nKSk7XG5cdFx0XHR0aGlzLl9lZGl0QnV0dG9uID0gJCgnPGJ1dHRvbj4nLCB7dHlwZTogJ2J1dHRvbicsIGNsYXNzOiAnay1idXR0b24gay1zZWNvbmRhcnkgbWwtMicsIHRpdGxlOiAnRWRpdCcsIGRpc2FibGVkOiB0cnVlfSkuYXBwZW5kKCQoJzxpIGNsYXNzPVwiZmFzIGZhLXBlblwiPjwvaT4nKSk7XG5cdFx0XHR0aGlzLl9yZW1vdmVCdXR0b24gPSAkKCc8YnV0dG9uPicsIHt0eXBlOiAnYnV0dG9uJywgY2xhc3M6ICdrLWJ1dHRvbiBrLXNlY29uZGFyeSBtbC0yJywgdGl0bGU6ICdSZW1vdmUnLCBkaXNhYmxlZDogdHJ1ZX0pLmFwcGVuZCgkKCc8aSBjbGFzcz1cImZhcyBmYS10aW1lc1wiPjwvaT4nKSk7XG5cblx0XHRcdGJ1dHRvbnMuYXBwZW5kKHRoaXMuX2FkZEJ1dHRvbik7XG5cdFx0XHRidXR0b25zLmFwcGVuZCh0aGlzLl9lZGl0QnV0dG9uKTtcblx0XHRcdGJ1dHRvbnMuYXBwZW5kKHRoaXMuX3JlbW92ZUJ1dHRvbik7XG5cblx0XHRcdC8vIEFwcGVuZCBidXR0b25zIGNvbnRhaW5lciB0byBtYWluIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKGJ1dHRvbnMpO1xuXG5cdFx0XHQvLyBDcmVhdGUgZWRpdCBkaWFsb2dcblx0XHRcdC8vIE5PVEU6IGRhdGEtZGlzbWlzcz1cIm1vZGFsXCIgb24gdGhlIGNsb3NlL2NhbmNlbCBidXR0b25zIHdhcyByZW1vdmVkIHRvIHdvcmsgYXJvdW5kIGFuIGlzc3VlIHdpdGggbmVzdGVkIG1vZGFscztcblx0XHRcdC8vIHRoZSBjdXN0b20gXCJkYXRhLWNhbmNlbFwiIGF0dHJpYnV0ZSBpcyB1c2VkIHRvIGFkZCBhIGN1c3RvbSBsaXN0ZW5lciB0byB0aGUgYnV0dG9uc1xuXHRcdFx0dGhpcy5fZWRpdERpYWxvZyA9ICQoYFxuXHRcdFx0XHQ8ZGl2IGNsYXNzPVwibW9kYWxcIiB0YWJpbmRleD1cIi0xXCIgcm9sZT1cImRpYWxvZ1wiIGFyaWEtbGFiZWxsZWRieT1cIm1vZGFsVGl0bGVcIiBhcmlhLWhpZGRlbj1cInRydWVcIiBkYXRhLWtleWJvYXJkPVwiZmFsc2VcIiBkYXRhLWJhY2tkcm9wPVwic3RhdGljXCI+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cIm1vZGFsLWRpYWxvZyBtb2RhbC1kaWFsb2ctY2VudGVyZWRcIiByb2xlPVwiZG9jdW1lbnRcIj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1jb250ZW50XCI+XG5cdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1oZWFkZXJcIj5cblx0XHRcdFx0XHRcdFx0XHQ8aDUgY2xhc3M9XCJtb2RhbC10aXRsZSB0ZXh0LXByaW1hcnlcIiBpZD1cIm1vZGFsVGl0bGVcIj4ke3RoaXMuX2RhdGEubGFiZWx9PC9oNT5cblx0XHRcdFx0XHRcdFx0XHQ8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImNsb3NlXCIgYXJpYS1sYWJlbD1cIkNsb3NlXCIgZGF0YS1jYW5jZWw9XCJtb2RhbFwiPlxuXHRcdFx0XHRcdFx0XHRcdFx0PHNwYW4gYXJpYS1oaWRkZW49XCJ0cnVlXCI+JnRpbWVzOzwvc3Bhbj5cblx0XHRcdFx0XHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1ib2R5IGluLWZsb3ctaW52YWxpZC1tc2dcIj5cblxuXHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cIm1vZGFsLWZvb3RlciBmbGV4LWNvbHVtblwiPlxuXHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJkLWZsZXggdy0xMDBcIj5cblx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJmbGV4LWdyb3ctMSB0ZXh0LWxlZnRcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJrLWJ1dHRvbiBrLXByaW1hcnlcIj4uLi48L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImZsZXgtZ3Jvdy0xIHRleHQtcmlnaHRcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJrLWJ1dHRvbiBrLXNlY29uZGFyeVwiIGRhdGEtY2FuY2VsPVwibW9kYWxcIj5DYW5jZWw8L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdGApO1xuXG5cdFx0XHQvLyBBZGQgbGlzdGVuZXIgdG8gZGlhbG9nIGhpZGUgZXZlbnRcblx0XHRcdHRoaXMuX2VkaXREaWFsb2cub24oJ2hpZGRlbi5icy5tb2RhbCcsICQucHJveHkodGhpcy5fb25FZGl0UGFuZWxIaWRkZW4sIHRoaXMpKTtcblxuXHRcdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIG1haW4gYnV0dG9uIGNsaWNrIGV2ZW50XG5cdFx0XHQkKCdidXR0b24uay1wcmltYXJ5JywgdGhpcy5fZWRpdERpYWxvZykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vblN1Ym1pdEJ0Q2xpY2ssIHRoaXMpKTtcblxuXHRcdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIGNsb3NlL2NhbmNlbCBidXR0b25zIGNsaWNrIGV2ZW50XG5cdFx0XHQkKCdidXR0b25bZGF0YS1jYW5jZWw9XCJtb2RhbFwiXScsIHRoaXMuX2VkaXREaWFsb2cpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25DYW5jZWxCdENsaWNrLCB0aGlzKSk7XG5cblx0XHRcdC8vIEFwcGVuZCBlZGl0IGRpYWxvZyB0byBtYWluIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKHRoaXMuX2VkaXREaWFsb2cpO1xuXHRcdH1cblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHdpZGdldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfaW5pdGlhbGl6ZSgpXG5cdHtcblx0XHRsZXQgY29sdW1ucyA9IFtdO1xuXHRcdGZvciAobGV0IHN1YkNvbmZpZ1BhcmFtIG9mIHRoaXMuX2RhdGEuZGVmYXVsdExpc3RJdGVtKVxuXHRcdHtcblx0XHRcdGxldCBjb2wgPSB7XG5cdFx0XHRcdGZpZWxkOiBzdWJDb25maWdQYXJhbS5uYW1lLFxuXHRcdFx0XHR0aXRsZTogc3ViQ29uZmlnUGFyYW0ubGFiZWwsXG5cdFx0XHRcdHdpZHRoOiAxMjBcblx0XHRcdH1cblxuXHRcdFx0Ly8gRGlzcGxheSBWIG9yIFggZm9yIGJvb2xlYW5zXG5cdFx0XHRpZiAodHlwZW9mIHN1YkNvbmZpZ1BhcmFtLnZhbHVlID09PSAnYm9vbGVhbicpXG5cdFx0XHRcdGNvbC50ZW1wbGF0ZSA9IGAjPSAke3N1YkNvbmZpZ1BhcmFtLm5hbWV9ID8gJzxpIGNsYXNzPVwiZmFzIGZhLWNoZWNrXCI+PC9pPicgOiAnPGkgY2xhc3M9XCJmYXMgZmEtdGltZXNcIj48L2k+JyAjYDtcblxuXHRcdFx0Ly8gSGlkZSBwYXNzd29yZHNcblx0XHRcdGlmIChzdWJDb25maWdQYXJhbS50eXBlID09ICdUZXh0SW5wdXQnICYmIHN1YkNvbmZpZ1BhcmFtLmF0dHJpYnV0ZXMgIT0gbnVsbCAmJiBzdWJDb25maWdQYXJhbS5hdHRyaWJ1dGVzLnR5cGUgPT0gJ3Bhc3N3b3JkJylcblx0XHRcdFx0Y29sLnRlbXBsYXRlID0gYCM9ICfigKInLnJlcGVhdChkYXRhLiR7c3ViQ29uZmlnUGFyYW0ubmFtZX0ubGVuZ3RoKSAjYDtcblxuXHRcdFx0Y29sdW1ucy5wdXNoKGNvbCk7XG5cdFx0fVxuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBncmlkXG5cdFx0bGV0IGdyaWRIdG1sID0gdGhpcy5fd2lkZ2V0SHRtbC5maW5kKGAjJHskLmVzY2FwZVNlbGVjdG9yKHRoaXMuX2RhdGEubmFtZSl9YCk7XG5cblx0XHRncmlkSHRtbC5rZW5kb0dyaWQoe1xuXHRcdFx0cmVzaXphYmxlOiB0cnVlLFxuXHRcdFx0c2VsZWN0YWJsZTogdGhpcy5fZGF0YS5lZGl0YWJsZSA/ICdyb3cnIDogZmFsc2UsXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25HcmlkU2VsZWN0aW9uQ2hhbmdlLCB0aGlzKSxcblx0XHRcdGNvbHVtbnM6IGNvbHVtbnMsXG5cdFx0XHRub1JlY29yZHM6IHtcblx0XHRcdFx0dGVtcGxhdGU6ICdObyBpdGVtcy4nXG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvLyBTYXZlIHJlZi4gdG8gd2lkZ2V0XG5cdFx0dGhpcy5fZ3JpZFdpZGdldCA9IGdyaWRIdG1sLmRhdGEoJ2tlbmRvR3JpZCcpO1xuXG5cdFx0Ly8gU2hvdyB0b290aXAgaWYgZ3JpZCdzIGNlbGwgY29udGVudCBleGNlZWRzIGNlbGwgd2lkdGggKGVsbGlwc2lzIGlzIGRpc3BsYXllZCBieSBLZW5kbyBHcmlkKVxuXHRcdGdyaWRIdG1sLmtlbmRvVG9vbHRpcCh7XG5cdFx0XHRmaWx0ZXI6ICd0ZCcsXG5cdFx0XHRzaG93OiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdC8vIE5ldmVyIHNob3cgdG9vbHRpcC4uLlxuXHRcdFx0XHR0aGlzLmNvbnRlbnQucGFyZW50KCkuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuXG5cdFx0XHRcdC8vIC4uLnVubGVzcyBjb250ZW50IGlzIHJldHVybmVkIChzZWUgYmVsb3cpIGR1ZSB0byBjZWxsIHdpZHRoIGJlaW5nIGV4Y2VlZGVkXG5cdFx0XHRcdGlmICh0aGlzLmNvbnRlbnQudGV4dCgpICE9ICcnKVxuXHRcdFx0XHRcdHRoaXMuY29udGVudC5wYXJlbnQoKS5jc3MoJ3Zpc2liaWxpdHknLCAndmlzaWJsZScpO1xuXHRcdFx0fSxcblx0XHRcdGhpZGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLmNvbnRlbnQucGFyZW50KCkuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuXHRcdFx0fSxcblx0XHRcdGNvbnRlbnQ6IGZ1bmN0aW9uKGUpIHtcblx0XHRcdFx0bGV0IGVsZW1lbnQgPSBlLnRhcmdldFswXTtcblx0XHRcdFx0aWYgKGVsZW1lbnQub2Zmc2V0V2lkdGggPCBlbGVtZW50LnNjcm9sbFdpZHRoKVxuXHRcdFx0XHRcdHJldHVybiBlLnRhcmdldC50ZXh0KCk7XG5cdFx0XHRcdGVsc2Vcblx0XHRcdFx0XHRyZXR1cm4gJyc7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvKlxuXHRcdC8vIEluaXRpYWxpemUgYnV0dG9uIHRvb2x0aXBzXG5cdFx0dGhpcy5fd2lkZ2V0SHRtbC5rZW5kb1Rvb2x0aXAoe1xuXHRcdFx0ZmlsdGVyOiAnYnV0dG9uJyxcblx0XHRcdGNvbnRlbnQ6IGZ1bmN0aW9uKGUpIHtcblx0XHRcdFx0cmV0dXJuIGA8ZGl2IGNsYXNzPVwiaGVscC10b29sdGlwXCI+JHtlLnRhcmdldC5kYXRhKCd0aXRsZScpfTwvZGl2PmA7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Ki9cblxuXHRcdC8vIEFkZCBidXR0b24gbGlzdGVuZXJzXG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0dGhpcy5fYWRkQnV0dG9uLmNsaWNrKCQucHJveHkodGhpcy5fb25BZGRDbGljaywgdGhpcykpO1xuXHRcdFx0dGhpcy5fZWRpdEJ1dHRvbi5jbGljaygkLnByb3h5KHRoaXMuX29uRWRpdENsaWNrLCB0aGlzKSk7XG5cdFx0XHR0aGlzLl9yZW1vdmVCdXR0b24uY2xpY2soJC5wcm94eSh0aGlzLl9vblJlbW92ZUNsaWNrLCB0aGlzKSk7XG5cdFx0fVxuXG5cdFx0Ly8gUHJvY2VlZCB3aXRoIGluaXRpYWxpemF0aW9uXG5cdFx0c3VwZXIuX2luaXRpYWxpemUoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgZGF0YXNvdXJjZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0bGV0IGRhdGFTb3VyY2UgPSBuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKHtcblx0XHRcdGRhdGE6IHRoaXMuX2RhdGEubGlzdFZhbHVlc1xuXHRcdH0pO1xuXG5cdFx0Ly8gUmVhZCBjdXJyZW50IGhvcml6b250YWwgc2Nyb2xsIHZhbHVlXG5cdFx0Y29uc3Qgc2Nyb2xsTGVmdCA9ICQoJy5rLWdyaWQtY29udGVudCcsIHRoaXMuX2dyaWRXaWRnZXQud3JhcHBlcikuc2Nyb2xsTGVmdCgpO1xuXG5cdFx0Ly8gQ2xlYXIgZ3JpZCBzZWxlY3Rpb24gaWYgYW55XG5cdFx0dGhpcy5fZ3JpZFdpZGdldC5jbGVhclNlbGVjdGlvbigpO1xuXG5cdFx0Ly8gU2V0IHVwZGF0ZWQgZ3JpZCdzIGRhdGFzb3VyY2Vcblx0XHR0aGlzLl9ncmlkV2lkZ2V0LnNldERhdGFTb3VyY2UoZGF0YVNvdXJjZSk7XG5cblx0XHQvLyBTZXQgaG9yaXpvbnRhbCBzY3JvbGxcblx0XHQkKCcuay1ncmlkLWNvbnRlbnQnLCB0aGlzLl9ncmlkV2lkZ2V0LndyYXBwZXIpLnNjcm9sbExlZnQoc2Nyb2xsTGVmdCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRpc2FibGVkIHN0YXRlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRFZGl0RW5hYmxlZCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQvLyBEZXNlbGVjdCBpdGVtXG5cdFx0XHR0aGlzLl9ncmlkV2lkZ2V0LmNsZWFyU2VsZWN0aW9uKCk7XG5cblx0XHRcdC8vIEVuYWJsZS9kaXNhYmxlIGdyaWRcblx0XHRcdHRoaXMuX2dyaWRXaWRnZXQud3JhcHBlci5hdHRyKCdkaXNhYmxlZCcsICF0aGlzLl9lZGl0RW5hYmxlZCk7XG5cblx0XHRcdC8vIEVuYWJsZSBcIkFkZFwiIGJ1dHRvblxuXHRcdFx0aWYgKHRoaXMuX2VkaXRFbmFibGVkKVxuXHRcdFx0XHR0aGlzLl9hZGRCdXR0b24uYXR0cignZGlzYWJsZWQnLCBmYWxzZSk7XG5cblx0XHRcdC8vIERpc2FibGUgYWxsIGJ1dHRvbnNcblx0XHRcdGVsc2Vcblx0XHRcdHtcblx0XHRcdFx0dGhpcy5fYWRkQnV0dG9uLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cdFx0XHRcdHRoaXMuX2VkaXRCdXR0b24uYXR0cignZGlzYWJsZWQnLCB0cnVlKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQnV0dG9uLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0X29uR3JpZFNlbGVjdGlvbkNoYW5nZShlKVxuXHR7XG5cdFx0bGV0IHNlbGVjdGVkUm93cyA9IHRoaXMuX2dyaWRXaWRnZXQuc2VsZWN0KCk7XG5cdFx0bGV0IHNlbGVjdGVkRGF0YUl0ZW1zID0gW107XG5cblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHNlbGVjdGVkUm93cy5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHRsZXQgZGF0YUl0ZW0gPSB0aGlzLl9ncmlkV2lkZ2V0LmRhdGFJdGVtKHNlbGVjdGVkUm93c1tpXSk7XG5cdFx0XHRzZWxlY3RlZERhdGFJdGVtcy5wdXNoKGRhdGFJdGVtKTtcblx0XHR9XG5cblx0XHQvLyBFbmFibGUvZGlzYWJsZSBlZGl0IGJ1dHRvblxuXHRcdGlmICh0aGlzLl9lZGl0QnV0dG9uKVxuXHRcdFx0dGhpcy5fZWRpdEJ1dHRvbi5wcm9wKCdkaXNhYmxlZCcsIHNlbGVjdGVkRGF0YUl0ZW1zLmxlbmd0aCA9PSAwKTtcblxuXHRcdC8vIEVuYWJsZS9kaXNhYmxlIHJlbW92ZSBidXR0b25cblx0XHRpZiAodGhpcy5fcmVtb3ZlQnV0dG9uKVxuXHRcdHtcblx0XHRcdC8vIEFsd2F5cyBkaXNhYmxlIGJ1dHRvbiBpZiBubyBsaXN0IGl0ZW0gaXMgc2VsZWN0ZWRcblx0XHRcdHRoaXMuX3JlbW92ZUJ1dHRvbi5wcm9wKCdkaXNhYmxlZCcsIHNlbGVjdGVkRGF0YUl0ZW1zLmxlbmd0aCA9PSAwKTtcblxuXHRcdFx0Ly8gQWxzbyBkaXNhYmxlIGJ1dHRvbiBpZiBkZW55RW1wdHkgPT0gdHJ1ZSBhbmQganVzdCBvbmUgaXRlbSByZW1haW5zIGluIHRoZSBsaXN0XG5cdFx0XHRpZiAodGhpcy5fZGF0YS5kZW55RW1wdHkpXG5cdFx0XHRcdHRoaXMuX3JlbW92ZUJ1dHRvbi5wcm9wKCdkaXNhYmxlZCcsIHRoaXMuX2RhdGEubGlzdEl0ZW1zLmxlbmd0aCA8PSAxKTtcblx0XHR9XG4gICAgfVxuXG5cdF9vblJlbW92ZUNsaWNrKClcblx0e1xuXHRcdGxldCBzZWxlY3RlZEluZGV4ID0gdGhpcy5fZ3JpZFdpZGdldC5zZWxlY3QoKS5pbmRleCgpO1xuXG5cdFx0Ly8gUmVtb3ZlIGl0ZW0gZnJvbSBsaXN0XG5cdFx0dGhpcy5fZGF0YS5yZW1vdmVMaXN0SXRlbShzZWxlY3RlZEluZGV4KTtcblxuXHRcdC8vIFJlZ2VuZXJhdGUgZGF0YWdyaWQncyBkYXRhc291cmNlXG5cdFx0dGhpcy5fc2V0V2lkZ2V0VmFsdWUoKTtcblx0fVxuXG5cdF9vbkFkZENsaWNrKClcblx0e1xuXHRcdC8vIENsb25lIGRlZmF1bHQgaXRlbSBhbmQgYWRkIHRvIGxpc3Rcblx0XHRsZXQgbmV3TGlzdEl0ZW0gPSBbXTtcblx0XHRmb3IgKGxldCBzdWJDUCBvZiB0aGlzLl9kYXRhLmRlZmF1bHRMaXN0SXRlbSlcblx0XHRcdG5ld0xpc3RJdGVtLnB1c2goc3ViQ1AuY2xvbmUodHJ1ZSkpO1xuXG5cdFx0Ly8gQ3JlYXRlIGVkaXQgcG9wdXBcblx0XHR0aGlzLl9vcGVuRWRpdFBhbmVsKG5ld0xpc3RJdGVtKTtcblx0fVxuXG5cdF9vbkVkaXRDbGljaygpXG5cdHtcblx0XHRsZXQgc2VsZWN0ZWRJbmRleCA9IHRoaXMuX2dyaWRXaWRnZXQuc2VsZWN0KCkuaW5kZXgoKTtcblxuXHRcdC8vIENsb25lIHNlbGVjdGVkIGl0ZW0gYW5kIGFkZCB0byBsaXN0XG5cdFx0bGV0IGNsb25lZExpc3RJdGVtID0gW107XG5cdFx0Zm9yIChsZXQgc3ViQ1Agb2YgdGhpcy5fZGF0YS5saXN0SXRlbXNbc2VsZWN0ZWRJbmRleF0pXG5cdFx0XHRjbG9uZWRMaXN0SXRlbS5wdXNoKHN1YkNQLmNsb25lKHRydWUpKTtcblxuXHRcdC8vIENyZWF0ZSBlZGl0IHBvcHVwXG5cdFx0dGhpcy5fb3BlbkVkaXRQYW5lbChjbG9uZWRMaXN0SXRlbSwgc2VsZWN0ZWRJbmRleCk7XG5cdH1cblxuXHRfb3BlbkVkaXRQYW5lbChzdWJDb25maWdQYXJhbXNBcnJheSwgZWRpdEluZGV4ID0gLTEpXG5cdHtcblx0XHQvLyBDaGVjayBpZiB0aGlzIGNvbmZpZ3VyYXRpb24gaXRlbSBpcyBpbnNpZGUgYSBtb2RhbCB3aW5kb3c7XG5cdFx0Ly8gaWYgeWVzLCB0aGUgZWRpdCBwYW5lbCAod2hpY2ggaXMgYSBtb2RhbCBhcyB3ZWxsKSBtdXN0IGJlIGNvbmZpZ3VyZWQgdG8gcmVtb3ZlIHRoZSBkYXJrIGJhY2tncm91bmRcblx0XHRpZiAoJCh0aGlzKS5wYXJlbnRzKCcubW9kYWwnKS5sZW5ndGggPiAwKVxuXHRcdFx0JCgnLm1vZGFsJywgJCh0aGlzKSkuYXR0cignZGF0YS1iYWNrZHJvcCcsIGZhbHNlKTtcblxuXHRcdC8vIENyZWF0ZSBkaWFsb2cgY29udGVudFxuXHRcdHRoaXMuX2l0ZW1FZGl0b3IgPSBuZXcgTGlzdEl0ZW1FZGl0b3IoKTtcblx0XHR0aGlzLl9pdGVtRWRpdG9yLmRhdGEgPSBzdWJDb25maWdQYXJhbXNBcnJheTtcblx0XHR0aGlzLl9pdGVtRWRpdG9yLmluZGV4ID0gZWRpdEluZGV4O1xuXG5cdFx0bGV0IGl0ZW1FZGl0b3IgPSAkKHRoaXMuX2l0ZW1FZGl0b3IpO1xuXG5cdFx0Ly8gQXBwZW5kIGNvbnRlbnQgdG8gZGlhbG9nXG5cdFx0JCgnLm1vZGFsLWJvZHknLCB0aGlzLl9lZGl0RGlhbG9nKS5hcHBlbmQoaXRlbUVkaXRvcik7XG5cblx0XHQvLyBTZXQgZGlhbG9nIG1haW4gYnV0dG9uIHRleHRcblx0XHQkKCdidXR0b24uay1wcmltYXJ5JywgdGhpcy5fZWRpdERpYWxvZykuaHRtbChlZGl0SW5kZXggPiAtMSA/ICc8aSBjbGFzcz1cImZhcyBmYS1wZW4gbXItMVwiPjwvaT5VcGRhdGUnIDogJzxpIGNsYXNzPVwiZmFzIGZhLXBsdXMgbXItMVwiPjwvaT5BZGQnKTtcblxuXHRcdC8vIERpc3BsYXkgZGlhbG9nXG5cdFx0dGhpcy5fZWRpdERpYWxvZy5tb2RhbCgnc2hvdycpO1xuXHR9XG5cblx0X29uU3VibWl0QnRDbGljaygpXG5cdHtcblx0XHRpZiAodGhpcy5faXRlbUVkaXRvci52YWxpZGF0ZSgpKVxuXHRcdHtcblx0XHRcdGxldCBkYXRhID0gdGhpcy5faXRlbUVkaXRvci5kYXRhO1xuXHRcdFx0bGV0IGluZGV4ID0gdGhpcy5faXRlbUVkaXRvci5pbmRleDtcblxuXHRcdFx0Ly8gSGlkZSBtb2RhbFxuXHRcdFx0dGhpcy5fZWRpdERpYWxvZy5tb2RhbCgnaGlkZScpO1xuXG5cdFx0XHQvLyBDb21wbGV0ZSBlZGl0aW5nXG5cdFx0XHR0aGlzLl9vbkVkaXRDb21wbGV0ZShkYXRhLCBpbmRleCk7XG5cdFx0fVxuXHR9XG5cblx0X29uQ2FuY2VsQnRDbGljaygpXG5cdHtcblx0XHQvLyBIaWRlIG1vZGFsXG5cdFx0dGhpcy5fZWRpdERpYWxvZy5tb2RhbCgnaGlkZScpO1xuXHR9XG5cblx0X29uRWRpdFBhbmVsSGlkZGVuKGUpXG5cdHtcblx0XHQvLyBSZW1vdmUgY29udGVudCBmcm9tIGRpYWxvZ1xuXHRcdHRoaXMuX2l0ZW1FZGl0b3IucmVtb3ZlKCk7XG5cblx0XHQvLyBTZXQgZGlhbG9nIG1haW4gYnV0dG9uIHRleHRcblx0XHQkKCdidXR0b24uay1wcmltYXJ5JywgdGhpcy5fZWRpdERpYWxvZykuaHRtbCgnLi4uJyk7XG5cblx0XHR0aGlzLl9pdGVtRWRpdG9yID0gbnVsbDtcblx0fVxuXG5cdF9vbkVkaXRDb21wbGV0ZShsaXN0SXRlbSwgZWRpdEluZGV4KVxuXHR7XG5cdFx0Ly8gQW4gZXhpc3RpbmcgbGlzdCBpdGVtIHdhcyB1cGRhdGVkXG5cdFx0aWYgKGVkaXRJbmRleCA+IC0xKVxuXHRcdFx0dGhpcy5fZGF0YS51cGRhdGVMaXN0SXRlbShsaXN0SXRlbSwgZWRpdEluZGV4KTtcblxuXHRcdC8vIEEgbmV3IGxpc3QgaXRlbSB3YXMgYWRkZWQ7IGFkZCBpdCB0byB0aGUgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXJcblx0XHRlbHNlXG5cdFx0XHR0aGlzLl9kYXRhLmFkZExpc3RJdGVtKGxpc3RJdGVtKTtcblxuXHRcdC8vIFJlZ2VuZXJhdGUgZGF0YWdyaWQncyBkYXRhc291cmNlXG5cdFx0dGhpcy5fc2V0V2lkZ2V0VmFsdWUoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1ncmlkJykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2NvbmZpZy1ncmlkJywgQ29uZmlnR3JpZCk7XG4iLCJleHBvcnQgY2xhc3MgQ29uZmlnTGFiZWwgZXh0ZW5kcyBIVE1MRWxlbWVudFxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKCk7XG5cblx0XHR0aGlzLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCdjb25maWctbGFiZWwnKTtcblx0fVxuXG5cdHNldCB2YWx1ZSh2YWwpXG5cdHtcblx0XHRpZiAodHlwZW9mIHZhbCA9PT0gJ2Jvb2xlYW4nKVxuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSAodmFsID8gJ3RydWUnIDogJ2ZhbHNlJyk7XG5cdFx0ZWxzZSBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpXG5cdFx0XHR0aGlzLmlubmVySFRNTCA9ICh2YWwgPyB2YWwgOiAwKTtcblx0XHRlbHNlXG5cdFx0XHR0aGlzLmlubmVySFRNTCA9ICh2YWwgIT0gJycgPyB2YWwgOiAnJm1kYXNoOycpO1xuXHR9XG5cblx0Z2V0IHZhbHVlKClcblx0e1xuXHRcdHJldHVybiB0aGlzLnRleHRDb250ZW50O1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnY29uZmlnLWxhYmVsJykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2NvbmZpZy1sYWJlbCcsIENvbmZpZ0xhYmVsKTtcbiIsImltcG9ydCB7Q29uZmlnRm9ybUl0ZW19IGZyb20gJy4vY29uZmlnLWZvcm0taXRlbSc7XG5pbXBvcnQge0NvbmZpZ0xhYmVsfSBmcm9tICcuL2NvbmZpZy1sYWJlbCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdOdW1lcmljU3RlcHBlciBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIGEgc2ltcGxlIGxhYmVsIGlzIHVzZWQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0XHRsZXQgY29uZmlnID0ge1xuXHRcdFx0XHR0eXBlOiAnbnVtYmVyJyxcblx0XHRcdFx0Y2xhc3M6ICdmb3JtLWNvbnRyb2wnLFxuXHRcdFx0XHRpZDogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHRuYW1lOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdCdkYXRhLXJvbGUnOiAnbnVtZXJpY3RleHRib3gnLFxuXHRcdFx0XHQnZGF0YS1yZXF1aXJlZC1tc2cnOiAnUmVxdWlyZWQnLFxuXHRcdFx0XHQnZGF0YS1mb3JtYXQnOiAnIycsXG5cdFx0XHRcdHJlcXVpcmVkOiAncmVxdWlyZWQnLFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0QXR0cmlidXRlcyhjb25maWcpO1xuXG5cdFx0XHQvLyBTZXQgYWRkaXRpb25hbCB3aWRnZXQgYXR0cmlidXRlcyBiYXNlZCBvbiB2YWxpZGF0aW9uIHJ1bGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gQ3JlYXRlIHdpZGdldCdzIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSAkKCc8aW5wdXQ+JywgY29uZmlnKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBDb25maWdMYWJlbCgpO1xuXG5cdFx0Ly8gUmV0dXJuIGNvbXBvbmVudFxuXHRcdHJldHVybiB0aGlzLl93aWRnZXRIdG1sO1xuXHR9XG5cblx0LyoqXG5cdCAqIEluaXRpYWxpemUgd2lkZ2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG4gICBfaW5pdGlhbGl6ZSgpXG4gICB7XG5cdCAgIGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHQgICB7XG5cdFx0ICAgLy8gSW5pdGlhbGl6ZSBrZW5kbyB3aWRnZXRcblx0XHQgICBrZW5kby5pbml0KHRoaXMuX3dpZGdldEh0bWwpO1xuXG5cdFx0ICAgLy8gU2F2ZSByZWYuIHRvIHdpZGdldFxuXHRcdCAgIHRoaXMuX2lubmVyV2lkZ2V0ID0gdGhpcy5fd2lkZ2V0SHRtbC5kYXRhKCdrZW5kb051bWVyaWNUZXh0Qm94Jyk7XG5cblx0XHQgICAvLyBFbmFibGUgdmFsdWUgY29tbWl0IGJpbmRpbmdcblx0XHQgICB0aGlzLl9pbm5lcldpZGdldC5iaW5kKCdjaGFuZ2UnLCAkLnByb3h5KHRoaXMuX29uVmFsdWVJbnB1dCwgdGhpcykpO1xuXHQgICB9XG5cblx0ICAgLy8gUHJvY2VlZCB3aXRoIGluaXRpYWxpemF0aW9uXG5cdCAgIHN1cGVyLl9pbml0aWFsaXplKCk7XG4gICB9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgdGhlIGxhYmVsIHRleHQgaXMgc2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRWYWx1ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX2lubmVyV2lkZ2V0LnZhbHVlKHRoaXMuX2RhdGEudmFsdWUpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsdWUgPSB0aGlzLl9kYXRhLnZhbHVlO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC5lbmFibGUodGhpcy5fZWRpdEVuYWJsZWQpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB2YWx1ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfb25WYWx1ZUlucHV0KGUpXG5cdHtcblx0XHQvLyBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdG8gbmV3IHZhbHVlXG5cdFx0dGhpcy5fZGF0YS52YWx1ZSA9IE51bWJlcih0aGlzLl9pbm5lcldpZGdldC52YWx1ZSgpKTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1udW1lcmljLXN0ZXBwZXInKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLW51bWVyaWMtc3RlcHBlcicsIENvbmZpZ051bWVyaWNTdGVwcGVyKTtcbiIsImltcG9ydCB7Q29uZmlnRm9ybUl0ZW19IGZyb20gJy4vY29uZmlnLWZvcm0taXRlbSc7XG5pbXBvcnQge0NvbmZpZ0xhYmVsfSBmcm9tICcuL2NvbmZpZy1sYWJlbCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdUZXh0SW5wdXQgZXh0ZW5kcyBDb25maWdGb3JtSXRlbVxue1xuXHRjb25zdHJ1Y3Rvcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKVxuXHR7XG5cdCAgICBzdXBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgd2lkZ2V0IHRvIHJlbmRlciB0aGUgQ29uZmlnUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCBhIHNpbXBsZSBsYWJlbCBpcyB1c2VkLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9nZW5lcmF0ZUlubmVyV2lkZ2V0KClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdC8vIFNldCB3aWRnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0bGV0IGNvbmZpZyA9IHtcblx0XHRcdFx0dHlwZTogJ3RleHQnLFxuXHRcdFx0XHRjbGFzczogJ2Zvcm0tY29udHJvbCBrLXRleHRib3gnLFxuXHRcdFx0XHRpZDogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHRuYW1lOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdGF1dG9jb21wbGV0ZTogJ29mZicsXG5cdFx0XHR9O1xuXG5cdFx0XHQvLyBTZXQgd2lkZ2V0IGF0dHJpYnV0ZXNcblx0XHRcdHRoaXMuX3NldFdpZGdldEF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gU2V0IGFkZGl0aW9uYWwgd2lkZ2V0IGF0dHJpYnV0ZXMgYmFzZWQgb24gdmFsaWRhdGlvbiBydWxlc1xuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gQ3JlYXRlIHdpZGdldCdzIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSAkKCc8aW5wdXQ+JywgY29uZmlnKTtcblxuXHRcdFx0Ly8gRW5hYmxlIHZhbHVlIGNvbW1pdCBiaW5kaW5nXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLm9uKCdjaGFuZ2UnLCAkLnByb3h5KHRoaXMuX29uVmFsdWVJbnB1dCwgdGhpcykpO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gbmV3IENvbmZpZ0xhYmVsKCk7XG5cblx0XHQvLyBSZXR1cm4gY29tcG9uZW50XG5cdFx0cmV0dXJuIHRoaXMuX3dpZGdldEh0bWw7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCB0aGUgbGFiZWwgdGV4dCBpcyBzZXQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldFZhbHVlKClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbC52YWwodGhpcy5fZGF0YS52YWx1ZSk7XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbC52YWx1ZSA9IHRoaXMuX2RhdGEudmFsdWU7XG5cblx0XHQvLyBUcmlnZ2VyIGV2ZW50XG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRpc2FibGVkIHN0YXRlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRFZGl0RW5hYmxlZCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwuYXR0cignZGlzYWJsZWQnLCAhdGhpcy5fZWRpdEVuYWJsZWQpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB2YWx1ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfb25WYWx1ZUlucHV0KGUpXG5cdHtcblx0XHQvLyBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdG8gbmV3IHZhbHVlXG5cdFx0dGhpcy5fZGF0YS52YWx1ZSA9IHRoaXMuX3dpZGdldEh0bWwudmFsKCk7XG5cblx0XHQvLyBUcmlnZ2VyIGV2ZW50XG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdjb25maWctdGV4dC1pbnB1dCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctdGV4dC1pbnB1dCcsIENvbmZpZ1RleHRJbnB1dCk7XG4iLCJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuaW1wb3J0IHtWZWN0b3IzRElucHV0fSBmcm9tICcuL3dpZGdldHMvdmVjdG9yLTNkLWlucHV0JztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ1ZlY3RvcjNEIGV4dGVuZHMgQ29uZmlnRm9ybUl0ZW1cbntcblx0Y29uc3RydWN0b3IoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZylcblx0e1xuXHQgICAgc3VwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlIHdpZGdldCB0byByZW5kZXIgdGhlIENvbmZpZ1BhcmFtZXRlciB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgYSBzaW1wbGUgbGFiZWwgaXMgdXNlZC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQvLyBDcmVhdGUgd2lkZ2V0J3MgaHRtbFxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBWZWN0b3IzRElucHV0KHRoaXMuX2RhdGEubmFtZSwgdGhpcy5fZGF0YS52YWxpZGF0b3IgPT0gJ2FvaScpO1xuXG5cdFx0XHQvLyBTZXQgd2lkZ2V0IGF0dHJpYnV0ZXNcblx0XHRcdHRoaXMuX3NldFdpZGdldEF0dHJpYnV0ZXModGhpcy5fd2lkZ2V0SHRtbCk7XG5cblx0XHRcdC8vIEVuYWJsZSB2YWx1ZSBjb21taXQgYmluZGluZ1xuXHRcdFx0JCh0aGlzLl93aWRnZXRIdG1sKS5vbignY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBDb25maWdMYWJlbCgpO1xuXG5cdFx0Ly8gUmV0dXJuIGNvbXBvbmVudFxuXHRcdHJldHVybiB0aGlzLl93aWRnZXRIdG1sO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgdGhlIGxhYmVsIHRleHQgaXMgc2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRWYWx1ZSgpXG5cdHtcblx0XHR0aGlzLl93aWRnZXRIdG1sLnZhbHVlID0gdGhpcy5fZGF0YS52YWx1ZTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgZGlzYWJsZWQgc3RhdGUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldEVkaXRFbmFibGVkKClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdCQodGhpcy5fd2lkZ2V0SHRtbCkuYXR0cignZGlzYWJsZWQnLCAhdGhpcy5fZWRpdEVuYWJsZWQpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl93aWRnZXRIdG1sLnZhbHVlO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnY29uZmlnLXZlY3Rvci0zZCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctdmVjdG9yLTNkJywgQ29uZmlnVmVjdG9yM0QpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbUZhY3Rvcnl9IGZyb20gJy4uLy4uLy4uL3V0aWxzL3VpYnVpbGRlci9jb25maWctZm9ybS1pdGVtLWZhY3RvcnknO1xuXG5leHBvcnQgY2xhc3MgTGlzdEl0ZW1FZGl0b3IgZXh0ZW5kcyBIVE1MRWxlbWVudFxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKCk7XG5cdH1cblxuXHRzZXQgZGF0YShzdWJDb25maWdQYXJhbXNBcnJheSlcblx0e1xuXHRcdHRoaXMuX2RhdGEgPSBzdWJDb25maWdQYXJhbXNBcnJheTtcblxuXHRcdHRoaXMuX2J1aWxkVmlldygpO1xuXHR9XG5cblx0Z2V0IGRhdGEoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2RhdGE7XG5cdH1cblxuXHRzZXQgaW5kZXgoaW5kZXgpXG5cdHtcblx0XHR0aGlzLl9pbmRleCA9IGluZGV4O1xuXHR9XG5cblx0Z2V0IGluZGV4KClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9pbmRleDtcblx0fVxuXG5cdF9idWlsZFZpZXcoKVxuXHR7XG5cdFx0Ly8gR2VuZXJhdGUgY29udGFpbmVyIGZvcm1cblx0XHR0aGlzLl9mb3JtID0gJCgnPGZvcm0+Jywge30pO1xuXG5cdFx0Ly8gQXBwZW5kIGZvcm1cblx0XHQkKHRoaXMpLmFwcGVuZCh0aGlzLl9mb3JtKTtcblxuXHRcdC8vIEdlbmVyYXRlIGZvcm0gZmllbGRzXG5cdFx0Zm9yIChsZXQgY29uZmlnUGFyYW0gb2YgdGhpcy5fZGF0YSlcblx0XHR7XG5cdFx0XHQvLyBDcmVhdGUgZm9ybSBpdGVtXG5cdFx0XHRsZXQgZm9ybUl0ZW0gPSBDb25maWdGb3JtSXRlbUZhY3RvcnkuY3JlYXRlKGNvbmZpZ1BhcmFtLCB0cnVlLCB0cnVlKTtcblx0XHRcdGZvcm1JdGVtLmRhdGEgPSBjb25maWdQYXJhbTtcblxuXHRcdFx0Ly8gQWRkIGZvcm0gaXRlbSB0byBmb3JtXG5cdFx0XHR0aGlzLl9mb3JtLmFwcGVuZChmb3JtSXRlbSk7XG5cdFx0fVxuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBrZW5kbyB2YWxpZGF0aW9uIG9uIGZvcm1cblx0XHR0aGlzLl92YWxpZGF0b3IgPSB0aGlzLl9mb3JtLmtlbmRvVmFsaWRhdG9yKHtcblx0XHRcdHZhbGlkYXRlT25CbHVyOiB0cnVlLFxuXHRcdFx0cnVsZXM6IHtcblx0XHRcdFx0Ly8gQWRkIHJ1bGUgdG8gdmFsaWRhdGUgQU9JIGZvcm0gaXRlbXM/XG5cdFx0XHRcdC8vIChzZWU6IGh0dHBzOi8vZGVtb3MudGVsZXJpay5jb20va2VuZG8tdWkvdmFsaWRhdG9yL2N1c3RvbS12YWxpZGF0aW9uKVxuXHRcdFx0XHRhb2k6IGZ1bmN0aW9uIChpbnB1dCkge1xuXHRcdFx0XHRcdGlmIChpbnB1dC5pcygnW2RhdGEtYW9pLW1zZ10nKSAmJiBpbnB1dC52YWwoKSAhPSAnJylcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRpZiAoaW5wdXQudmFsKCkgPT0gJzAsMCwwJylcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXHRcdFx0fVxuXHRcdH0pLmRhdGEoJ2tlbmRvVmFsaWRhdG9yJyk7XG5cdH1cblxuXHR2YWxpZGF0ZSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fdmFsaWRhdG9yLnZhbGlkYXRlKCk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdsaXN0LWl0ZW0tZWRpdG9yJykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2xpc3QtaXRlbS1lZGl0b3InLCBMaXN0SXRlbUVkaXRvcik7XG4iLCJleHBvcnQgY2xhc3MgVmVjdG9yM0RJbnB1dCBleHRlbmRzIEhUTUxFbGVtZW50XG57XG5cdGNvbnN0cnVjdG9yKGlkLCBpc1ZhbGlkYWJsZSlcblx0e1xuXHQgICAgc3VwZXIoKTtcblxuXHRcdHRoaXMuaWQgPSBpZDtcblx0XHR0aGlzLm5hbWUgPSBpZDtcblxuXHRcdHRoaXMuX2lzVmFsaWRhYmxlID0gaXNWYWxpZGFibGU7XG5cblx0XHR0aGlzLl9pbml0aWFsaXplKCk7XG5cdH1cblxuXHRzZXQgZW5hYmxlQ2xlYXIodmFsdWUpXG5cdHtcblx0XHRpZiAodmFsdWUpXG5cdFx0XHR0aGlzLl9jbGVhckJ1dHRvbi5zaG93KCk7XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fY2xlYXJCdXR0b24uaGlkZSgpO1xuXHR9XG5cblx0c2V0IGFsbG93TmVnYXRpdmUodmFsdWUpXG5cdHtcblx0XHRpZiAodmFsdWUpXG5cdFx0e1xuXHRcdFx0dGhpcy5fd2lkZ2V0WC5zZXRPcHRpb25zKCB7bWluOiBudWxsfSApO1xuXHRcdFx0dGhpcy5fd2lkZ2V0WS5zZXRPcHRpb25zKCB7bWluOiBudWxsfSApO1xuXHRcdFx0dGhpcy5fd2lkZ2V0Wi5zZXRPcHRpb25zKCB7bWluOiBudWxsfSApO1xuXHRcdH1cblx0fVxuXG5cdHNldCB2YWx1ZSh2YWwpXG5cdHtcblx0XHR2YXIgY29vcmRzID0gdmFsLnNwbGl0KCcsJyk7XG5cblx0XHRpZiAoY29vcmRzLmxlbmd0aCA+PSAxKVxuXHRcdFx0dGhpcy5fd2lkZ2V0WC52YWx1ZShjb29yZHNbMF0pO1xuXG5cdFx0aWYgKGNvb3Jkcy5sZW5ndGggPj0gMilcblx0XHRcdHRoaXMuX3dpZGdldFkudmFsdWUoY29vcmRzWzFdKTtcblxuXHRcdGlmIChjb29yZHMubGVuZ3RoID49IDMpXG5cdFx0XHR0aGlzLl93aWRnZXRaLnZhbHVlKGNvb3Jkc1syXSk7XG5cblx0XHRpZiAodGhpcy5faXNWYWxpZGFibGUpXG5cdFx0XHR0aGlzLl9pbnB1dFZhbC52YWwodGhpcy52YWx1ZSk7XG5cdH1cblxuXHRnZXQgdmFsdWUoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX3dpZGdldFgudmFsdWUoKSA9PSBudWxsICYmIHRoaXMuX3dpZGdldFkudmFsdWUoKSA9PSBudWxsICYmIHRoaXMuX3dpZGdldFoudmFsdWUoKSA9PSBudWxsKVxuXHRcdFx0cmV0dXJuICcnO1xuXHRcdGVsc2Vcblx0XHRcdHJldHVybiB0aGlzLl93aWRnZXRYLnZhbHVlKCkgKyAnLCcgKyB0aGlzLl93aWRnZXRZLnZhbHVlKCkgKyAnLCcgKyB0aGlzLl93aWRnZXRaLnZhbHVlKCk7XG5cdH1cblxuXHRfaW5pdGlhbGl6ZSgpXG5cdHtcblx0XHQvLyBHZW5lcmF0ZSBjb250YWluZXIgZm9ybVxuXHRcdHRoaXMuX2NvbnRhaW5lciA9ICQoJzxkaXY+Jywge1xuXHRcdFx0Y2xhc3M6ICdmb3JtLWlubGluZSdcblx0XHR9KTtcblxuXHRcdC8vIEFwcGVuZCBjb250YWluZXJcblx0XHQkKHRoaXMpLmFwcGVuZCh0aGlzLl9jb250YWluZXIpO1xuXG5cdFx0Ly8gU2V0IGlucHV0cyBjb25maWd1cmF0aW9uXG5cdFx0bGV0IGNvbmZpZ0h0bWwgPSB7XG5cdFx0XHR0eXBlOiAnbnVtYmVyJyxcblx0XHRcdGNsYXNzOiAnZm9ybS1jb250cm9sIHNob3J0LTQnLFxuXHRcdH07XG5cblx0XHQvLyBTZXQgd2lkZ2V0IGNvbmZpZ3VyYXRpb25cblx0XHRsZXQgY29uZmlnV2lkZ2V0ID0ge1xuXHRcdFx0bWluOiAwLFxuXHRcdFx0c3Bpbm5lcnM6IGZhbHNlLFxuXHRcdFx0Zm9ybWF0OiAnIy4jIyMjIyMnLFxuXHRcdFx0ZGVjaW1hbHM6IDYsXG5cdFx0XHRyb3VuZDogZmFsc2UsXG5cdFx0XHRzcGlubmVyczogZmFsc2UsXG5cdFx0XHRyZXN0cmljdERlY2ltYWxzOiBmYWxzZSxcblx0XHRcdGNoYW5nZTogJC5wcm94eSh0aGlzLl9vbkNoYW5nZSwgdGhpcylcblx0XHR9O1xuXG5cdFx0Ly8gQ3JlYXRlIHdpZGdldHNcblx0XHR0aGlzLl9pbnB1dFggPSAkKCc8aW5wdXQ+JywgY29uZmlnSHRtbCk7XG5cdFx0dGhpcy5fY29udGFpbmVyLmFwcGVuZCh0aGlzLl9pbnB1dFgpO1xuXHRcdHRoaXMuX3dpZGdldFggPSB0aGlzLl9pbnB1dFgua2VuZG9OdW1lcmljVGV4dEJveChjb25maWdXaWRnZXQpLmRhdGEoJ2tlbmRvTnVtZXJpY1RleHRCb3gnKTtcblxuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQoJzxzcGFuIGNsYXNzPVwicHgtMVwiPiw8L3NwYW4+Jyk7XG5cblx0XHR0aGlzLl9pbnB1dFkgPSAkKCc8aW5wdXQ+JywgY29uZmlnSHRtbCk7XG5cdFx0dGhpcy5fY29udGFpbmVyLmFwcGVuZCh0aGlzLl9pbnB1dFkpO1xuXHRcdHRoaXMuX3dpZGdldFkgPSB0aGlzLl9pbnB1dFkua2VuZG9OdW1lcmljVGV4dEJveChjb25maWdXaWRnZXQpLmRhdGEoJ2tlbmRvTnVtZXJpY1RleHRCb3gnKTtcblxuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQoJzxzcGFuIGNsYXNzPVwicHgtMVwiPiw8L3NwYW4+Jyk7XG5cblx0XHR0aGlzLl9pbnB1dFogPSAkKCc8aW5wdXQ+JywgY29uZmlnSHRtbCk7XG5cdFx0dGhpcy5fY29udGFpbmVyLmFwcGVuZCh0aGlzLl9pbnB1dFopO1xuXHRcdHRoaXMuX3dpZGdldFogPSB0aGlzLl9pbnB1dFoua2VuZG9OdW1lcmljVGV4dEJveChjb25maWdXaWRnZXQpLmRhdGEoJ2tlbmRvTnVtZXJpY1RleHRCb3gnKTtcblxuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQoJzxzcGFuIGNsYXNzPVwicHgtMVwiPjwvc3Bhbj4nKTsgLy8gQWRkaXRpb25hbCBzcGFjZXJcblxuXHRcdC8vIENyZWF0ZSBpbnZpc2libGUgZmllbGQgdG8gYXBwbHkgb3ZlcmFsbCB2YWxpZGF0aW9uXG5cdFx0aWYgKHRoaXMuX2lzVmFsaWRhYmxlKVxuXHRcdHtcblx0XHRcdHRoaXMuX2lucHV0VmFsID0gJCgnPGlucHV0PicsIHtuYW1lOiBgJHt0aGlzLm5hbWV9LWN1c3RvbS12YWxpZGF0ZWAsICdkYXRhLWFvaS1tc2cnOiAnVmFsdWVzIGNhblxcJ3QgYWxsIGJlIDAnfSk7XG5cdFx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKHRoaXMuX2lucHV0VmFsKTtcblx0XHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQoYDxzcGFuIGNsYXNzPVwiay1pbnZhbGlkLW1zZ1wiIGRhdGEtZm9yPVwiJHt0aGlzLm5hbWV9LWN1c3RvbS12YWxpZGF0ZVwiPjwvc3Bhbj5gKVxuXHRcdFx0dGhpcy5faW5wdXRWYWwuaGlkZSgpO1xuXHRcdH1cblxuXHRcdC8vIENyZWF0ZSBhbmQgYXBwZW5kIENsZWFyIGJ1dHRvblxuXHRcdHRoaXMuX2NsZWFyQnV0dG9uID0gJCgnPGJ1dHRvbj4nLCB7dHlwZTogJ2J1dHRvbicsIGNsYXNzOiAnay1idXR0b24gay1zZWNvbmRhcnkgbXktMScsIHRpdGxlOiAnQ2xlYXInfSkuYXBwZW5kKCQoJzxpIGNsYXNzPVwiZmFzIGZhLXRpbWVzXCI+PC9pPicpKTtcblx0XHR0aGlzLl9jbGVhckJ1dHRvbi5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uQ2xlYXJDbGljaywgdGhpcykpO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQodGhpcy5fY2xlYXJCdXR0b24pO1xuXG5cdFx0Ly8gSGlkZSBidXR0b24gYnkgZGVmYXVsdFxuXHRcdHRoaXMuX2NsZWFyQnV0dG9uLmhpZGUoKTtcblx0fVxuXG5cdF9vbkNoYW5nZSgpXG5cdHtcblx0XHQvLyBFbXB0eSBzdHJpbmdzIGFyZSBub3QgYWxsb3dlZFxuXHRcdGlmICh0aGlzLl93aWRnZXRYLnZhbHVlKCkgPT0gbnVsbClcblx0XHRcdHRoaXMuX3dpZGdldFgudmFsdWUoMCk7XG5cblx0XHRpZiAodGhpcy5fd2lkZ2V0WS52YWx1ZSgpID09IG51bGwpXG5cdFx0XHR0aGlzLl93aWRnZXRZLnZhbHVlKDApO1xuXG5cdFx0aWYgKHRoaXMuX3dpZGdldFoudmFsdWUoKSA9PSBudWxsKVxuXHRcdFx0dGhpcy5fd2lkZ2V0Wi52YWx1ZSgwKTtcblxuXHRcdHRoaXMuX2Rpc3BhdGNoQ29tbWl0KCk7XG5cdH1cblxuXHRfb25DbGVhckNsaWNrKClcblx0e1xuXHRcdHRoaXMuX3dpZGdldFgudmFsdWUoJycpO1xuXHRcdHRoaXMuX3dpZGdldFkudmFsdWUoJycpO1xuXHRcdHRoaXMuX3dpZGdldFoudmFsdWUoJycpO1xuXG5cdFx0dGhpcy5fZGlzcGF0Y2hDb21taXQoKTtcblx0fVxuXG5cdF9kaXNwYXRjaENvbW1pdCgpXG5cdHtcblx0XHRpZiAodGhpcy5faXNWYWxpZGFibGUpXG5cdFx0XHR0aGlzLl9pbnB1dFZhbC52YWwodGhpcy52YWx1ZSk7XG5cblx0XHR0aGlzLmRpc3BhdGNoRXZlbnQobmV3IEV2ZW50KCdjaGFuZ2UnKSk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCd2ZWN0b3ItM2QtaW5wdXQnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgndmVjdG9yLTNkLWlucHV0JywgVmVjdG9yM0RJbnB1dCk7XG4iLCJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuLi8uLi9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctZm9ybS1pdGVtJztcblxuaW1wb3J0IHtDb25maWdOdW1lcmljU3RlcHBlcn0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLW51bWVyaWMtc3RlcHBlcic7XG5pbXBvcnQge0NvbmZpZ1RleHRJbnB1dH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLXRleHQtaW5wdXQnO1xuaW1wb3J0IHtDb25maWdDaGVja0JveH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWNoZWNrLWJveCc7XG5pbXBvcnQge0NvbmZpZ0Ryb3BEb3duTGlzdH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWRyb3AtZG93bi1saXN0JztcbmltcG9ydCB7Q29uZmlnR3JpZH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWdyaWQnO1xuaW1wb3J0IHtDb25maWdEdWFsTGlzdH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWR1YWwtbGlzdCc7XG5pbXBvcnQge0NvbmZpZ1ZlY3RvcjNEfSBmcm9tICcuLi8uLi9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctdmVjdG9yLTNkJztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0Zvcm1JdGVtRmFjdG9yeVxue1xuXHRzdGF0aWMgY3JlYXRlKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cgPSBmYWxzZSlcblx0e1xuXHRcdHN3aXRjaCAoY29uZmlnUGFyYW0udHlwZSlcblx0XHR7XG5cdFx0XHRjYXNlICdUZXh0SW5wdXQnOlxuXHRcdFx0XHRyZXR1cm4gbmV3IENvbmZpZ1RleHRJbnB1dChjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0NoZWNrQm94Jzpcblx0XHRcdFx0cmV0dXJuIG5ldyBDb25maWdDaGVja0JveChjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ051bWVyaWNTdGVwcGVyJzpcblx0XHRcdFx0cmV0dXJuIG5ldyBDb25maWdOdW1lcmljU3RlcHBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0NvbWJvQm94Jzpcblx0XHRcdFx0cmV0dXJuIG5ldyBDb25maWdEcm9wRG93bkxpc3QoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdEYXRhR3JpZCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnR3JpZChjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0R1YWxMaXN0Jzpcblx0XHRcdFx0cmV0dXJuIG5ldyBDb25maWdEdWFsTGlzdChjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1ZlY3RvcjNEJzpcblx0XHRcdFx0cmV0dXJuIG5ldyBDb25maWdWZWN0b3IzRChjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnRm9ybUl0ZW0oY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7IC8vIFdpbGwgbG9nIGFuIGVycm9yIGZvciBtaXNzaW5nIGZvcm0gaXRlbSB0eXBlXG5cdFx0fVxuXHR9XG59XG4iLCJpbXBvcnQge0NvbmZpZ3VyYXRpb25QYXJhbWV0ZXJ9IGZyb20gJy4vY29uZmlndXJhdGlvbi1wYXJhbWV0ZXInO1xuaW1wb3J0IHtDb25maWdGb3JtSXRlbUZhY3Rvcnl9IGZyb20gJy4vY29uZmlnLWZvcm0taXRlbS1mYWN0b3J5JztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0ludGVyZmFjZUJ1aWxkZXJcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdFx0Ly8gU2V0IHNvbWUgY29uc3RhbnRzXG5cdFx0dGhpcy5UQUJfUFJFRklYID0gJ3RhYi0nXG5cdFx0dGhpcy5UQUJfUEFORV9QUkVGSVggPSAndGFicGFuZS0nO1xuXHRcdHRoaXMuU0VQQVJBVE9SX0JFRk9SRSA9ICdiZWZvcmUnO1xuXHRcdHRoaXMuU0VQQVJBVE9SX0FGVEVSID0gJ2FmdGVyJztcblx0fVxuXG5cdGR1bXAobW9kaWZpZWRPbmx5ID0gZmFsc2UpXG5cdHtcblx0XHRsZXQgZHVtcFN0ciA9ICcnO1xuXG5cdFx0Zm9yIChsZXQgY3Agb2YgdGhpcy5fY29uZmlnUGFyYW1zKVxuXHRcdHtcblx0XHRcdGlmIChtb2RpZmllZE9ubHkpXG5cdFx0XHR7XG5cdFx0XHRcdGlmIChjcC5pc01vZGlmaWVkKVxuXHRcdFx0XHRcdGR1bXBTdHIgKz0gY3AudG9TdHJpbmcoKSArICdcXG4nO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZVxuXHRcdFx0XHRkdW1wU3RyICs9IGNwLnRvU3RyaW5nKCkgKyAnXFxuJztcblx0XHR9XG5cblx0XHRjb25zb2xlLmxvZyhkdW1wU3RyKTtcblx0fVxuXG5cdGJ1aWxkSW50ZXJmYWNlKGRhdGEsIG1haW5Db250YWluZXJJZCwgZGlzYWJsZUVkaXQgPSBmYWxzZSwgdGFiU3VmZml4ID0gJycpXG5cdHtcblx0XHR0aGlzLl9tYWluQ29udGFpbmVySWQgPSBtYWluQ29udGFpbmVySWQ7XG5cdFx0dGhpcy5fY29uZmlnUGFyYW1zID0gbmV3IEFycmF5KCk7XG5cdFx0dGhpcy5fdmFsaWRhdG9yID0gbnVsbDtcblxuXHRcdGxldCBoYXNOZXdGb3JtSXRlbSA9IGZhbHNlO1xuXG5cdFx0Ly9jb25zb2xlLmxvZyhkYXRhLmdldER1bXAoKSlcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgZGF0YS5zaXplKCk7IGkrKylcblx0XHR7XG5cdFx0XHQvLyBQQVJTRSBEQVRBXG5cblx0XHRcdGxldCBjb25maWdQYXJhbSA9IENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIuZnJvbVNmc09iamVjdChkYXRhLmdldChpKSk7XG5cdFx0XHR0aGlzLl9jb25maWdQYXJhbXMucHVzaChjb25maWdQYXJhbSk7XG5cblx0XHRcdC8vIEdldCB0YWIgYW5kIHRhYiBwYW5lIGlkIGZyb20gZ3JvdXAgaWRcblx0XHRcdGNvbnN0IHRhYklkID0gdGhpcy5UQUJfUFJFRklYICsgY29uZmlnUGFyYW0uY2F0ZWdvcnlJZCArICh0YWJTdWZmaXggPyAnXycgKyB0YWJTdWZmaXggOiAnJyk7XG5cdFx0XHRjb25zdCB0YWJQYW5lSWQgPSB0aGlzLlRBQl9QQU5FX1BSRUZJWCArIGNvbmZpZ1BhcmFtLmNhdGVnb3J5SWQgKyAodGFiU3VmZml4ID8gJ18nICsgdGFiU3VmZml4IDogJycpO1xuXG5cdFx0XHQvLyBCVUlMRCBJTlRFUkZBQ0UgOjogVEFCU1xuXG5cdFx0XHQvLyBDaGVjayBpZiBhIHRhYiBzcGVjaWZpYyBmb3IgdGhpcyBncm91cCBhbHJlYWR5IGV4aXN0cyBpbnNpZGUgdGhlIG1haW5Db250YWluZXI6IGlmIG5vdCwgY3JlYXRlIGl0XG5cdFx0XHQvLyAoYSB0YWIgYWxyZWFkeSBleGlzdHMgaWYgaXQgd2FzIGNyZWF0ZWQgaW4gYSBwcmV2aW91cyBsb29wKVxuXHRcdFx0bGV0IHRhYiA9ICQoYCMke21haW5Db250YWluZXJJZH0gPiAjdGFicyAjJHt0YWJJZH1gKTtcblxuXHRcdFx0aWYgKHRhYi5sZW5ndGggPT0gMClcblx0XHRcdHtcblx0XHRcdFx0Ly8gQ3JlYXRlIHRhYiBmb3IgdGFiIHBhbmVcblx0XHRcdFx0dGFiID0gJCgnPGxpPicsIHtjbGFzczogJ25hdi1pdGVtJ30pO1xuXHRcdFx0XHR0YWIuYXBwZW5kKCQoJzxhPicsIHtcblx0XHRcdFx0XHRjbGFzczogJ25hdi1saW5rJyArIChpID09IDAgPyAnIGFjdGl2ZScgOiAnJyksXG5cdFx0XHRcdFx0aWQ6IHRhYklkLFxuXHRcdFx0XHRcdCdkYXRhLXRvZ2dsZSc6ICd0YWInLFxuXHRcdFx0XHRcdGhyZWY6ICcjJyArIHRhYlBhbmVJZCxcblx0XHRcdFx0XHRyb2xlOiAndGFiJyxcblx0XHRcdFx0XHQnYXJpYS1jb250cm9scyc6IHRhYlBhbmVJZCxcblx0XHRcdFx0XHQnYXJpYS1zZWxlY3RlZCc6IChpID09IDAgPyAndHJ1ZScgOiAnZmFsc2UnKSxcblx0XHRcdFx0XHRodG1sOiBjb25maWdQYXJhbS5jYXRlZ29yeSxcblx0XHRcdFx0fSkpO1xuXG5cdFx0XHRcdC8vIEFkZCB0YWIgdG8gY29udGFpbmVyXG5cdFx0XHRcdCQoYCMke21haW5Db250YWluZXJJZH0gPiAjdGFic2ApLmFwcGVuZCh0YWIpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBCVUlMRCBJTlRFUkZBQ0UgOjogVEFCIFBBTkVTXG5cblx0XHRcdC8vIENoZWNrIGlmIGEgdGFiIHBhbmUgc3BlY2lmaWMgZm9yIHRoaXMgZ3JvdXAgYWxyZWFkeSBleGlzdHMgaW5zaWRlIHRoZSBtYWluQ29udGFpbmVyOiBpZiBub3QsIGNyZWF0ZSBpdFxuXHRcdFx0Ly8gKGEgdGFiIHBhbmUgYWxyZWFkeSBleGlzdHMgaWYgaXQgd2FzIGNyZWF0ZWQgaW4gYSBwcmV2aW91cyBsb29wIG9yIGlmIGl0IGV4aXN0cyBzdGF0aWNhbGx5IGluIHRoZSBodG1sIC0gaW4gY2FzZSBpdCBpcyBuZWVkZWQgdG8gYWRkIHNvbWUgc3RhdGljIGNvbnRlbnQpXG5cdFx0XHRsZXQgdGFiUGFuZSA9ICQoYCMke21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gIyR7dGFiUGFuZUlkfWApO1xuXG5cdFx0XHRpZiAodGFiUGFuZS5sZW5ndGggPT0gMClcblx0XHRcdHtcblx0XHRcdFx0Ly8gQ3JlYXRlIHRhYiBwYW5lXG5cdFx0XHRcdHRhYlBhbmUgPSAkKCc8ZGl2PicsIHtcblx0XHRcdFx0XHRjbGFzczogJ3RhYi1wYW5lJyArIChpID09IDAgPyAnIHNob3cgYWN0aXZlJyA6ICcnKSxcblx0XHRcdFx0XHRpZDogdGFiUGFuZUlkLFxuXHRcdFx0XHRcdHJvbGU6ICd0YWJwYW5lbCcsXG5cdFx0XHRcdFx0J2FyaWEtbGFiZWxsZWRieSc6IHRhYklkLFxuXHRcdFx0XHRcdCdkYXRhLWR5bmFtaWMnOiAndHJ1ZScsXG5cdFx0XHRcdH0pO1xuXG5cdFx0XHRcdC8vIEFkZCB0YWIgcGFuZSB0byBjb250YWluZXJcblx0XHRcdFx0JChgIyR7bWFpbkNvbnRhaW5lcklkfSA+ICN0YWJQYW5lbHNgKS5hcHBlbmQodGFiUGFuZSk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEJVSUxEIElOVEVSRkFDRSA6OiBUQUIgUEFORVMnIEZPUk1cblxuXHRcdFx0Ly8gQ2hlY2sgaWYgYSBmb3JtIGFscmVhZHkgZXhpc3RzIGluc2lkZSB0aGUgdGFiIHBhbmU6IGlmIG5vdCwgY3JlYXRlIGl0XG5cdFx0XHRsZXQgZm9ybSA9IHRhYlBhbmUuZmluZCgnZm9ybScpO1xuXG5cdFx0XHRpZiAoZm9ybS5sZW5ndGggPT0gMClcblx0XHRcdHtcblx0XHRcdFx0Ly8gQ3JlYXRlIGZvcm1cblx0XHRcdFx0Zm9ybSA9ICQoJzxmb3JtPicsIHtcblx0XHRcdFx0XHRjbGFzczogJycsXG5cdFx0XHRcdFx0YXV0b2NvbXBsZXRlOiAnb2ZmJ1xuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHQvLyBDcmVhdGUgYW4gaW5uZXIgZmllbGRzZXQ7IHRoaXMgbWlnaHQgYmUgdXNlZnVsIHRvIGVhc2lseSBkaXNhYmxlIHRoZSB3aG9sZSBmb3JtIGF0IG9uY2UgKGFjdHVhbGx5IHdlIGRvbid0IHVzZSBpdCBiZWNhdXNlIEtlbmRvIHdpZGdldHMgYXJlIG5vdCBkaXNhYmxlZCBhdXRvbWF0aWNhbGx5KVxuXHRcdFx0XHRmb3JtLmFwcGVuZChcblx0XHRcdFx0XHQkKCc8ZmllbGRzZXQ+Jywge1xuXHRcdFx0XHRcdFx0Y2xhc3M6ICcnXG5cdFx0XHRcdFx0fSlcblx0XHRcdFx0KTtcblxuXHRcdFx0XHQvLyBBZGQgZm9ybSB0byB0YWIgcGFuZVxuXHRcdFx0XHR0YWJQYW5lLnByZXBlbmQoZm9ybSk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEdldCBmaWVsZHNldCwgd2hpY2ggaXMgdGhlIGFjdHVhbCBmb3JtIGl0ZW1zIGNvbnRhaW5lclxuXHRcdFx0bGV0IGZpZWxkc2V0ID0gZm9ybS5maW5kKCdmaWVsZHNldCcpO1xuXG5cdFx0XHQvLyBCVUlMRCBJTlRFUkZBQ0UgOjogVEFCIFBBTkVTJyBGT1JNIElURU1TXG5cblx0XHRcdC8vIENoZWNrIGlmIGZvcm0gaXRlbSBhbHJlYWR5IGV4aXN0cyBpbiBmaWVsZHNldDsgaWYgeWVzLCBqdXN0IHVwZGF0ZSBpdHMgZGF0YVxuXHRcdFx0bGV0IGZvcm1JdGVtID0gZmllbGRzZXQuZmluZChgI2Zvcm0taXRlbS0keyQuZXNjYXBlU2VsZWN0b3IoY29uZmlnUGFyYW0ubmFtZSl9YCk7XG5cblx0XHRcdGlmIChmb3JtSXRlbS5sZW5ndGggPT0gMClcblx0XHRcdHtcblx0XHRcdFx0aGFzTmV3Rm9ybUl0ZW0gPSB0cnVlO1xuXG5cdFx0XHRcdGZvcm1JdGVtID0gQ29uZmlnRm9ybUl0ZW1GYWN0b3J5LmNyZWF0ZShjb25maWdQYXJhbSwgIWRpc2FibGVFZGl0KTtcblxuXHRcdFx0XHQvLyBBZGQgc2VwYXJhdG9yIGJlZm9yZVxuXHRcdFx0XHRpZiAoY29uZmlnUGFyYW0uc2VwYXJhdG9yICE9IG51bGwgJiYgY29uZmlnUGFyYW0uc2VwYXJhdG9yLnBvcyA9PSAnYmVmb3JlJylcblx0XHRcdFx0XHRmaWVsZHNldC5hcHBlbmQodGhpcy5fYnVpbGRTZXBhcmF0b3IoY29uZmlnUGFyYW0uc2VwYXJhdG9yKSk7XG5cblx0XHRcdFx0Ly8gQWRkIGZvcm0gaXRlbSB0byBmb3JtXG5cdFx0XHRcdGZpZWxkc2V0LmFwcGVuZChmb3JtSXRlbSk7XG5cblx0XHRcdFx0Ly8gQWRkIHNlcGFyYXRvciBhZnRlclxuXHRcdFx0XHRpZiAoY29uZmlnUGFyYW0uc2VwYXJhdG9yICE9IG51bGwgJiYgY29uZmlnUGFyYW0uc2VwYXJhdG9yLnBvcyA9PSAnYWZ0ZXInKVxuXHRcdFx0XHRcdGZpZWxkc2V0LmFwcGVuZCh0aGlzLl9idWlsZFNlcGFyYXRvcihjb25maWdQYXJhbS5zZXBhcmF0b3IpKTtcblx0XHRcdH1cblx0XHRcdGVsc2Vcblx0XHRcdFx0Zm9ybUl0ZW1bMF0uZGF0YSA9IGNvbmZpZ1BhcmFtO1xuXHRcdH1cblxuXHRcdC8vIEFkZCBsaXN0ZW5lciB0byBzaG93IGhlbHAgdG9vbHRpcHNcblx0XHRsZXQgYWxsVGFiUGFuZXMgPSAkKGAjJHttYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+IGRpdi50YWItcGFuZWApO1xuXHRcdGFsbFRhYlBhbmVzLmtlbmRvVG9vbHRpcCh7XG5cdFx0XHRmaWx0ZXI6ICdpW3RpdGxlXS5oZWxwJyxcblx0XHRcdHBvc2l0aW9uOiAncmlnaHQnLFxuXHRcdFx0d2lkdGg6ICcyNTBweCcsXG5cdFx0XHRjb250ZW50OiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdHJldHVybiBgPGRpdiBjbGFzcz1cImhlbHAtdG9vbHRpcFwiPiR7ZS50YXJnZXQuZGF0YSgndGl0bGUnKX08L2Rpdj5gO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBrZW5kbyB2YWxpZGF0aW9uIG9uIGZvcm1zJyBtYWluIGNvbnRhaW5lclxuXHRcdHRoaXMuX3ZhbGlkYXRvciA9ICQoYCMke21haW5Db250YWluZXJJZH1gKS5rZW5kb1ZhbGlkYXRvcih7XG5cdFx0XHR2YWxpZGF0ZU9uQmx1cjogdHJ1ZSxcblx0XHRcdHJ1bGVzOiB7XG5cdFx0XHRcdC8vIEFkZCBydWxlIHRvIHZhbGlkYXRlIEFPSSBmb3JtIGl0ZW1zXG5cdFx0XHRcdC8vIChzZWU6IGh0dHBzOi8vZGVtb3MudGVsZXJpay5jb20va2VuZG8tdWkvdmFsaWRhdG9yL2N1c3RvbS12YWxpZGF0aW9uKVxuXHRcdFx0XHRhb2k6IGZ1bmN0aW9uIChpbnB1dCkge1xuXHRcdFx0XHRcdGlmIChpbnB1dC5pcygnW2RhdGEtYW9pLW1zZ10nKSAmJiBpbnB1dC52YWwoKSAhPSAnJylcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRpZiAoaW5wdXQudmFsKCkgPT0gJzAsMCwwJylcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXHRcdFx0fVxuXHRcdH0pLmRhdGEoJ2tlbmRvVmFsaWRhdG9yJyk7XG5cdH1cblxuXHRkZXN0cm95SW50ZXJmYWNlKClcblx0e1xuXHRcdC8vIERlc3Ryb3kgYWxsIEtlbmRvIHdpZGdldHMgaW4gZm9ybXNcblx0XHRrZW5kby5kZXN0cm95KCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gZGl2LnRhYi1wYW5lID4gZm9ybWApKTtcblxuXHRcdC8vIFJlbW92ZSBhbGwgdGFic1xuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFic2ApLmVtcHR5KCk7XG5cblx0XHQvLyBSZW1vdmUgZHluYW1pYyB0YWIgcGFuZXMgKHRhYiBwYW5lcyBjcmVhdGVkIGJ5IEludGVyZmFjZSBCdWlsZGVyKVxuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gZGl2LnRhYi1wYW5lW2RhdGEtZHluYW1pYz1cInRydWVcIl1gKS5yZW1vdmUoKTtcblxuXHRcdC8vIFJlbW92ZSBmb3JtIGluc2lkZSBzdGF0aWMgdGFiIHBhbmVzIChwcmVkZWZpbmVkIHRhYiBwYW5lcyBpbiBodG1sKVxuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gZGl2LnRhYi1wYW5lID4gZm9ybWApLnJlbW92ZSgpO1xuXG5cdFx0Ly8gUmVtb3ZlIFwiYWN0aXZlXCIgY2xhc3MgZnJvbSBzdGF0aWMgdGFiIHBhbmVzIChvdGhlcndpc2UgdGhpcyBjbGFzcyBtZXNzZXMgd2l0aCB0aGUgdGFiIG5hdmlnYXRvciBmdW5jdGlvbmluZylcblx0XHQkKGAjJHt0aGlzLl9tYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+IGRpdi50YWItcGFuZWApLnJlbW92ZUNsYXNzKCdhY3RpdmUnKTtcblx0fVxuXG5cdGRpc2FibGVJbnRlcmZhY2UoZGlzYWJsZSlcblx0e1xuXHRcdC8vIEVuYWJsZS9kaXNhYmxlIGFsbCBjb25maWcgZm9ybSBpdGVtc1xuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gKltpZF49J2Zvcm0taXRlbS0nXWApLnByb3AoJ2VkaXRFbmFibGVkJywgIWRpc2FibGUpO1xuXHR9XG5cblx0X2J1aWxkU2VwYXJhdG9yKHNlcGFyYXRvcilcblx0e1xuXHRcdGlmIChzZXBhcmF0b3IudGV4dCA9PSBudWxsKVxuXHRcdFx0cmV0dXJuICQoYDxociBjbGFzcz1cImNvbmZpZy1mb3JtLXNlcGFyYXRvclwiPmApO1xuXG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuICQoYDxsYWJlbCBjbGFzcz1cImNvbmZpZy1mb3JtLXNlcGFyYXRvci1sYWJlbCBtYi0zXCI+JHtzZXBhcmF0b3IudGV4dH08L2xhYmVsPmApO1xuXHR9XG5cblx0Z2V0Q2hhbmdlZERhdGEoKVxuXHR7XG5cdFx0bGV0IGNoYW5nZXMgPSBuZXcgU0ZTMlguU0ZTQXJyYXkoKTtcblxuXHRcdGZvciAodmFyIGNwIG9mIHRoaXMuX2NvbmZpZ1BhcmFtcylcblx0XHR7XG5cdFx0XHRpZiAoY3AuaXNNb2RpZmllZClcblx0XHRcdFx0Y2hhbmdlcy5hZGRTRlNPYmplY3QoY3AudG9TZnNPYmplY3QoKSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNoYW5nZXM7XG5cdH1cblxuXHRyZXNldElzTW9kaWZpZWQoKVxuXHR7XG5cdFx0Zm9yIChsZXQgY3Agb2YgdGhpcy5fY29uZmlnUGFyYW1zKVxuXHRcdHtcblx0XHRcdGlmIChjcC5pc01vZGlmaWVkKVxuXHRcdFx0XHRjcC5yZXNldElzTW9kaWZpZWQoKTtcblx0XHR9XG5cdH1cblxuXHRjaGVja0lzVmFsaWQoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbGlkYXRvci52YWxpZGF0ZSgpO1xuXHR9XG5cblx0cmVzZXRWYWxpZGF0aW9uKClcblx0e1xuXHRcdHRoaXMuX3ZhbGlkYXRvci5oaWRlTWVzc2FnZXMoKTtcblxuXHRcdC8vIFRoZSBtZXRob2QgYWJvdmUgZG9lc24ndCByZW1vdmUgdGhlIGstaW52YWxpZCBjbGFzc2VzIGFuZCBhcmlhLWludmFsaWQ9XCJ0cnVlXCIgYXR0cmlidXRlcyBmcm9tIGlucHV0c1xuXHRcdC8vIExldCdzIGRvIGl0IG1hbnVhbGx5XG5cdFx0JChgIyR7dGhpcy5fbWFpbkNvbnRhaW5lcklkfSAuay1pbnZhbGlkYCkucmVtb3ZlQ2xhc3MoJ2staW52YWxpZCcpO1xuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gW2FyaWEtaW52YWxpZD1cInRydWVcIl1gKS5yZW1vdmVBdHRyKCdhcmlhLWludmFsaWQnKTtcblx0fVxuXG5cdGdldENvbmZpZ0Zvcm1JdGVtKGNvbmZpZ1BhcmFtTmFtZSlcblx0e1xuXHRcdGxldCBmb3JtSXRlbSA9ICQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH1gKS5maW5kKGAjZm9ybS1pdGVtLSR7JC5lc2NhcGVTZWxlY3Rvcihjb25maWdQYXJhbU5hbWUpfWApO1xuXG5cdFx0aWYgKGZvcm1JdGVtLmxlbmd0aCA+IDApXG5cdFx0XHRyZXR1cm4gZm9ybUl0ZW1bMF07XG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIG51bGw7XG5cdH1cblxuXHRhY3RpdmF0ZUZpcnN0VGFiUGFuZWwoKVxuXHR7XG5cdFx0bGV0IGNvbmZpZ1BhcmFtID0gdGhpcy5fY29uZmlnUGFyYW1zWzBdO1xuXHRcdGNvbnN0IHRhYlBhbmVJZCA9IHRoaXMuVEFCX1BBTkVfUFJFRklYICsgY29uZmlnUGFyYW0uY2F0ZWdvcnlJZDtcblx0XHRsZXQgdGFiUGFuZSA9ICQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gIyR7dGFiUGFuZUlkfWApO1xuXHRcdHRhYlBhbmUuYWRkQ2xhc3MoJ3Nob3cgYWN0aXZlJyk7XG5cdH1cbn1cbiIsImV4cG9ydCBjbGFzcyBDb25maWd1cmF0aW9uUGFyYW1ldGVyXG57XG5cdHN0YXRpYyBmcm9tU2ZzT2JqZWN0KGVsZW1lbnQpXG5cdHtcblx0XHRsZXQgY3AgPSBuZXcgQ29uZmlndXJhdGlvblBhcmFtZXRlcigpO1xuXG5cdFx0Ly8gUGFyc2UgY29tbW9uIGRhdGFcblx0XHRjcC5uYW1lID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ25hbWUnKTtcblx0XHRjcC5sYWJlbCA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCdsYWJlbCcpO1xuXHRcdGNwLmNhdGVnb3J5ID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ2NhdGVnb3J5Jyk7XG5cdFx0Y3AudG9vbHRpcCA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCd0b29sdGlwJyk7XG5cdFx0Y3AudHlwZSA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCd0eXBlJyk7XG5cdFx0Y3AudmFsdWUgPSBlbGVtZW50LmdldCgndmFsdWUnKTtcblx0XHRjcC52YWxpZGF0b3IgPSBlbGVtZW50LmdldFV0ZlN0cmluZygndmFsaWRhdG9yJyk7XG5cdFx0Y3AuZWRpdGFibGUgPSAoZWxlbWVudC5jb250YWluc0tleSgnZWRpdCcpID8gZWxlbWVudC5nZXRCb29sKCdlZGl0JykgOiB0cnVlKTtcblx0XHRjcC50cmlnZ2VyID0gKGVsZW1lbnQuY29udGFpbnNLZXkoJ3RyaWdnZXInKSA/IGVsZW1lbnQuZ2V0Qm9vbCgndHJpZ2dlcicpIDogZmFsc2UpO1xuXHRcdGNwLnRyaWdnZXJEYXRhID0gZWxlbWVudC5nZXRTRlNBcnJheSgndHJpZ2dlckRhdGEnKTtcblx0XHRjcC5jbGllbnRPbmx5ID0gKGVsZW1lbnQuY29udGFpbnNLZXkoJ2NsaWVudE9ubHknKSA/IGVsZW1lbnQuZ2V0Qm9vbCgnY2xpZW50T25seScpIDogZmFsc2UpO1xuXHRcdGNwLmRhdGFQcm92aWRlciA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCdkYXRhUHJvdmlkZXInKTtcblxuXHRcdC8vIFBhcnNlIGNvbXBvbmVudCBzcGVjaWZpYyBhdHRyaWJ1dGVzXG5cdFx0bGV0IHRtcEF0dHJpYnV0ZXMgPSBlbGVtZW50LmdldFNGU09iamVjdCgnYXR0cmlidXRlcycpO1xuXHRcdGlmICh0bXBBdHRyaWJ1dGVzICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0bGV0IGF0dHJpYnV0ZXMgPSB7fTtcblxuXHRcdFx0bGV0IGtleXMgPSB0bXBBdHRyaWJ1dGVzLmdldEtleXNBcnJheSgpO1xuXHRcdFx0Zm9yIChsZXQga2V5IG9mIGtleXMpXG5cdFx0XHRcdGF0dHJpYnV0ZXNba2V5XSA9IHRtcEF0dHJpYnV0ZXMuZ2V0KGtleSk7XG5cblx0XHRcdGNwLmF0dHJpYnV0ZXMgPSBhdHRyaWJ1dGVzO1xuXHRcdH1cblxuXHRcdC8vIFBhcnNlIHNlcGFyYXRvciBzZXR0aW5nc1xuXHRcdGxldCB0bXBTZXBhcmF0b3IgPSBlbGVtZW50LmdldFNGU09iamVjdCgnc2VwYXJhdG9yJyk7XG5cdFx0aWYgKHRtcFNlcGFyYXRvciAhPSBudWxsKVxuXHRcdHtcblx0XHRcdGxldCBzZXBhcmF0b3IgPSB7fTtcblxuXHRcdFx0bGV0IGtleXMxID0gdG1wU2VwYXJhdG9yLmdldEtleXNBcnJheSgpO1xuXHRcdFx0Zm9yIChsZXQga2V5MSBvZiBrZXlzMSlcblx0XHRcdFx0c2VwYXJhdG9yW2tleTFdID0gdG1wU2VwYXJhdG9yLmdldChrZXkxKTtcblxuXHRcdFx0Y3Auc2VwYXJhdG9yID0gc2VwYXJhdG9yO1xuXHRcdH1cblxuXHRcdC8vIFBhcnNlIGRlZmF1bHQgbGlzdCBpdGVtXG5cdFx0bGV0IHRtcERlZmF1bHRMaXN0SXRlbSA9IGVsZW1lbnQuZ2V0U0ZTQXJyYXkoJ2RlZmF1bHRMaXN0SXRlbScpO1xuXHRcdGlmICh0bXBEZWZhdWx0TGlzdEl0ZW0gIT0gbnVsbCAmJiB0bXBEZWZhdWx0TGlzdEl0ZW0uc2l6ZSgpID4gMClcblx0XHR7XG5cdFx0XHRsZXQgZGVmYXVsdExpc3RJdGVtID0gW107XG5cblx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdG1wRGVmYXVsdExpc3RJdGVtLnNpemUoKTsgaSsrKVxuXHRcdFx0XHRkZWZhdWx0TGlzdEl0ZW0ucHVzaChDb25maWd1cmF0aW9uUGFyYW1ldGVyLmZyb21TZnNPYmplY3QodG1wRGVmYXVsdExpc3RJdGVtLmdldFNGU09iamVjdChpKSkpO1xuXG5cdFx0XHRjcC5kZWZhdWx0TGlzdEl0ZW0gPSBkZWZhdWx0TGlzdEl0ZW07XG5cblx0XHRcdC8vIFBhcnNlIGxpc3QgdmFsdWVzXG5cdFx0XHRsZXQgbGlzdFZhbHVlcyA9IFtdO1xuXG5cdFx0XHRsZXQgdG1wTGlzdFZhbHVlcyA9IGVsZW1lbnQuZ2V0U0ZTQXJyYXkoJ2xpc3RWYWx1ZXMnKTtcblx0XHRcdGlmICh0bXBMaXN0VmFsdWVzICE9IG51bGwgJiYgdG1wTGlzdFZhbHVlcy5zaXplKCkgPiAwKVxuXHRcdFx0e1xuXHRcdFx0XHRmb3IgKGxldCB2ID0gMDsgdiA8IHRtcExpc3RWYWx1ZXMuc2l6ZSgpOyB2KyspXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsZXQgbGlzdFZhbHVlT2JqID0gdG1wTGlzdFZhbHVlcy5nZXRTRlNPYmplY3Qodik7XG5cdFx0XHRcdFx0bGV0IG9iaiA9IHt9O1xuXG5cdFx0XHRcdFx0bGV0IGtleXMyID0gbGlzdFZhbHVlT2JqLmdldEtleXNBcnJheSgpO1xuXHRcdFx0XHRcdGZvciAobGV0IGtleTIgb2Yga2V5czIpXG5cdFx0XHRcdFx0XHRvYmpba2V5Ml0gPSBsaXN0VmFsdWVPYmouZ2V0KGtleTIpO1xuXG5cdFx0XHRcdFx0bGlzdFZhbHVlcy5wdXNoKG9iaik7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Y3AubGlzdFZhbHVlcyA9IGxpc3RWYWx1ZXM7XG5cblx0XHRcdC8vIElmIHdlIGhhdmUgYSBsaXN0LCBvbiB0aGUgc2VydmVyLXNpZGUgaXRlbXMgY291bGQgYmUgcmVwcmVzZW50ZWQgYnkgYSBjbGFzc1xuXHRcdFx0Y3AuY2xhenogPSBlbGVtZW50LmdldFV0ZlN0cmluZygnY2xhenonKTtcblxuXHRcdFx0Ly8gQXZvaWQgbGlzdCB0byBiZSBlbXB0aWVkXG5cdFx0XHRjcC5kZW55RW1wdHkgPSAoZWxlbWVudC5jb250YWluc0tleSgnZGVueUVtcHR5JykgPyBlbGVtZW50LmdldEJvb2woJ2RlbnlFbXB0eScpIDogZmFsc2UpO1xuXHRcdH1cblxuXHRcdHJldHVybiBjcDtcblx0fVxuXG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHRcdC8qIENPTlNUQU5UUyAqL1xuXHRcdHRoaXMuREVGQVVMVF9DQVRFR09SWV9OQU1FID0gJ0dlbmVyYWwnO1xuXHRcdHRoaXMuREVGQVVMVF9DQVRFR09SWV9JRCA9ICdnZW5lcmFsJztcblxuXHRcdC8qIFBVQkxJQyBWQVJTICovXG5cblx0XHR0aGlzLm5hbWUgPSAnJztcblx0XHR0aGlzLmxhYmVsID0gJyc7XG5cdFx0dGhpcy50b29sdGlwID0gJyc7XG5cdFx0dGhpcy50eXBlID0gbnVsbDtcblx0XHR0aGlzLnRyaWdnZXIgPSBmYWxzZTtcblx0XHR0aGlzLnRyaWdnZXJEYXRhID0gbnVsbDtcblx0XHR0aGlzLmNsaWVudE9ubHkgPSBmYWxzZTtcblx0XHR0aGlzLmVkaXRhYmxlID0gdHJ1ZTtcblx0XHR0aGlzLmF0dHJpYnV0ZXMgPSBudWxsO1xuXHRcdHRoaXMuZGF0YVByb3ZpZGVyID0gbnVsbDtcblxuXHRcdHRoaXMuc2VwYXJhdG9yID0gbnVsbDtcdFx0XHQvLyBQYXJhbWV0ZXIgdXNlZCB0byBjcmVhdGUgYSBzZXBhcmF0b3IgYmVmb3JlIG9yIGFmdGVyIHRoZSBjb25maWcgcGFyYW1ldGVyXG5cdFx0dGhpcy5kZWZhdWx0TGlzdEl0ZW0gPSBudWxsO1x0Ly8gTGlzdCBvZiBzdWItQ29uZmlndXJhdGlvblBhcmFtZXRlcnMsIGVhY2ggY29udGFpbmluZyB0aGUgZGVmYXVsdCB2YWx1ZXNcblx0XHR0aGlzLmNsYXp6ID0gbnVsbDtcdFx0XHRcdC8vIE5hbWUgb2YgdGhlIGNsYXNzIHJlcHJlc2VudGluZyB0aGUgbGlzdCBpdGVtIChub3QgdXNlZCBpbiBjYXNlIG9mIHByaW1pdGV2ZSBkYXRhIHR5cGVzKVxuXHRcdHRoaXMuZGVueUVtcHR5ID0gZmFsc2U7XHRcdFx0Ly8gRGlzYWxsb3cgdG8gZW1wdHkgYSBsaXN0IChEYXRhR3JpZCBjb25maWcgcGFyYW1ldGVyIHR5cGUgb25seSlcblxuXHRcdC8qIFBSSVZBVEUgVkFSUyAqL1xuXG5cdFx0dGhpcy5fY2F0ZWdvcnkgPSB0aGlzLkRFRkFVTFRfQ0FURUdPUllfTkFNRTtcblx0XHR0aGlzLl9jYXRlZ29yeUlkID0gdGhpcy5ERUZBVUxUX0NBVEVHT1JZX0lEO1xuXHRcdHRoaXMuX3ZhbHVlID0gbnVsbDtcblx0XHR0aGlzLl9pbml0aWFsVmFsdWUgPSBudWxsO1x0XHQvLyBTYXZlIHRoZSBpbml0aWFsIHZhbHVlIG9mIHRoZSBjb25maWd1cmF0aW9uIHBhcmFtZXRlciwgdG8gY2hlY2sgaWYgdGhlIHZhbHVlIHdhcyBtb2RpZmllZFxuXHRcdHRoaXMuX3ZhbGlkYXRvciA9IG51bGw7XG5cblx0XHR0aGlzLl9saXN0SXRlbXMgPSBbXTtcdFx0XHQvLyBBcnJheSBvZiBhcnJheXMgb2YgQ29uZmlndXJhdGlvblBhcmFtZXRlcnNcblx0XHR0aGlzLl9saXN0SXRlbXNDaGFuZ2VkID0gZmFsc2U7XHQvLyBGbGFnIHRvIGJlIHNldCBpbiBjYXNlIGEgbGlzdCBpdGVtIGlzIGFkZGVkIG9yIHJlbW92ZWRcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIEdFVFRFUlMgLyBTRVRURVJTXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0c2V0IGNhdGVnb3J5KHZhbClcblx0e1xuXHRcdGlmICh2YWwpXG5cdFx0e1xuXHRcdFx0dGhpcy5fY2F0ZWdvcnkgPSB2YWw7XG5cdFx0XHR0aGlzLl9zZXRJZEZyb21DYXRlZ29yeU5hbWUodGhpcy5fY2F0ZWdvcnkpO1xuXHRcdH1cblx0fVxuXG5cdGdldCBjYXRlZ29yeSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fY2F0ZWdvcnk7XG5cdH1cblxuXHRzZXQgdmFsdWUodmFsKVxuXHR7XG5cdFx0aWYgKHRoaXMuX3ZhbHVlICE9IHZhbClcblx0XHR7XG5cdFx0XHQvLyBJZiB2YWx1ZSBpcyBudWxsLCB0aGVuIHdlIGFyZSBzZXR0aW5nIHRoaXMgZm9yIHRoZSBmaXJzdCB0aW1lIGFuZFxuXHRcdFx0Ly8gd2Ugd2FudCB0byBzYXZlIHRoZSBpbml0aWFsIHZhbHVlLCB0byBjaGVjayBsYXRlciBpZiBpdCBoYXMgYmVlbiBtb2RpZmllZFxuXHRcdFx0aWYgKHRoaXMuX3ZhbHVlID09IG51bGwpXG5cdFx0XHRcdHRoaXMuX2luaXRpYWxWYWx1ZSA9IHZhbDtcblxuXHRcdFx0dGhpcy5fdmFsdWUgPSB2YWw7XG5cdFx0fVxuXHR9XG5cblx0Z2V0IHZhbHVlKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl92YWx1ZTtcblx0fVxuXG5cdHNldCB2YWxpZGF0b3IodmFsKVxuXHR7XG5cdFx0aWYgKHZhbClcblx0XHRcdHRoaXMuX3ZhbGlkYXRvciA9IHZhbDtcblx0fVxuXG5cdGdldCB2YWxpZGF0b3IoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbGlkYXRvcjtcblx0fVxuXG5cdC8qKlxuXHQgKiBBbiBhcnJheSBvZiBvYmplY3RzOyBlYWNoIG9iamVjdCBjb250YWlucyB0aGUgbmFtZS12YWx1ZSBwYWlycyB1c2VkIHRvXG5cdCAqIHBvcHVsYXRlIHRoZSBsaXN0IG9mIHN1Yi1jb25maWd1cmF0aW9uIHBhcmFtZXRlcnMgYXJyYXlzLCBiYXNlZCBvbiBkZWZhdWx0TGlzdEl0ZW0uXG5cdCAqL1xuXHRzZXQgbGlzdFZhbHVlcyhhcnIpXG5cdHtcblx0XHR0aGlzLl9zZXRTdWJDb25maWd1cmF0aW9uUGFyYW1zKGFycik7XG5cdH1cblxuXHRnZXQgbGlzdFZhbHVlcygpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fZ2V0U3ViQ29uZmlndXJhdGlvblBhcmFtc1ZhbHVlcygpO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8gR0VUVEVSUyBPTkxZXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0Z2V0IGlzTW9kaWZpZWQoKVxuXHR7XG5cdFx0bGV0IF9pc01vZGlmaWVkID0gZmFsc2U7XG5cblx0XHQvLyBJZiB0aGUgcGFyYW1ldGVyIGlzIHVzZWQgb24gdGhlIGNsaWVudCBvbmx5IChmb3IgZXhhbXBsZSBpbiBhIGN1c3RvbSB0cmlnZ2VyKVxuXHRcdC8vIHRoZW4gd2UgbmV2ZXIgaGF2ZSB0byBjb25zaWRlciBpdCBhcyBtb2RpZmllZCwgdG8gcHJldmVudCBpdCBiZWluZyBzZW50IHRvIHRoZSBzZXJ2ZXJcblx0XHRpZiAoIXRoaXMuY2xpZW50T25seSlcblx0XHR7XG5cdFx0XHRpZiAodGhpcy5fdmFsdWUgIT0gdGhpcy5faW5pdGlhbFZhbHVlIHx8IHRoaXMuX2xpc3RJdGVtc0NoYW5nZWQpXG5cdFx0XHRcdF9pc01vZGlmaWVkID0gdHJ1ZTtcblx0XHRcdGVsc2Vcblx0XHRcdHtcblx0XHRcdFx0Ly8gQ2hlY2sgc3ViIHBhcmFtZXRlcnNcblx0XHRcdFx0b3V0ZXJMb29wOiBmb3IgKGxldCBsaXN0SXRlbSBvZiB0aGlzLl9saXN0SXRlbXMpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRmb3IgKGxldCBzdWJDUCBvZiBsaXN0SXRlbSlcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRpZiAoc3ViQ1AuaXNNb2RpZmllZClcblx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0X2lzTW9kaWZpZWQgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRicmVhayBvdXRlckxvb3A7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIF9pc01vZGlmaWVkO1xuXHR9XG5cblx0Z2V0IGNhdGVnb3J5SWQoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2NhdGVnb3J5SWQ7XG5cdH1cblxuXHRnZXQgbGlzdEl0ZW1zKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9saXN0SXRlbXM7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBQVUJMSUMgTUVUSE9EU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdC8qKlxuXHQgKiBSZXR1cm4gYSBjbG9uZSBvZiB0aGlzIENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIuXG5cdCAqL1xuXHRjbG9uZShjbG9uZVZhbHVlID0gZmFsc2UpXG5cdHtcblx0XHRsZXQgY3AgPSBuZXcgQ29uZmlndXJhdGlvblBhcmFtZXRlcigpO1xuXHRcdGNwLm5hbWUgPSB0aGlzLm5hbWU7XG5cdFx0Y3AubGFiZWwgPSB0aGlzLmxhYmVsO1xuXHRcdGNwLmNhdGVnb3J5ID0gdGhpcy5jYXRlZ29yeTtcblx0XHRjcC50b29sdGlwID0gdGhpcy50b29sdGlwO1xuXHRcdGNwLnR5cGUgPSB0aGlzLnR5cGU7XG5cdFx0Y3AudmFsaWRhdG9yID0gdGhpcy52YWxpZGF0b3I7XG5cdFx0Y3AudHJpZ2dlciA9IHRoaXMudHJpZ2dlcjtcblx0XHRjcC50cmlnZ2VyRGF0YSA9ICh0aGlzLnRyaWdnZXJEYXRhICE9IG51bGwgPyBTRlMyWC5TRlNBcnJheS5uZXdGcm9tQmluYXJ5RGF0YSh0aGlzLnRyaWdnZXJEYXRhLnRvQmluYXJ5KCkpIDogbnVsbCk7XG5cdFx0Y3AuY2xpZW50T25seSA9IHRoaXMuY2xpZW50T25seTtcblx0XHRjcC5kYXRhUHJvdmlkZXIgPSB0aGlzLmRhdGFQcm92aWRlcjtcblxuXHRcdGlmIChjbG9uZVZhbHVlKVxuXHRcdFx0Y3AudmFsdWUgPSB0aGlzLnZhbHVlO1xuXG5cdFx0aWYgKHRoaXMuYXR0cmlidXRlcyAhPSBudWxsKVxuXHRcdHtcblx0XHRcdGNwLmF0dHJpYnV0ZXMgPSBuZXcgT2JqZWN0KCk7XG5cdFx0XHRmb3IgKGxldCBzMSBpbiB0aGlzLmF0dHJpYnV0ZXMpXG5cdFx0XHRcdGNwLmF0dHJpYnV0ZXNbczFdID0gdGhpcy5hdHRyaWJ1dGVzW3MxXTtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5zZXBhcmF0b3IgIT0gbnVsbClcblx0XHR7XG5cdFx0XHRjcC5zZXBhcmF0b3IgPSBuZXcgT2JqZWN0KClcblx0XHRcdGZvciAobGV0IHMyIGluIHRoaXMuc2VwYXJhdG9yKVxuXHRcdFx0XHRjcC5zZXBhcmF0b3JbczJdID0gdGhpcy5zZXBhcmF0b3JbczJdO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLmRlZmF1bHRMaXN0SXRlbSAhPSBudWxsKVxuXHRcdHtcblx0XHRcdGxldCBjbG9uZWREZWZhdWx0TGlzdEl0ZW1zID0gW107XG5cblx0XHRcdGZvciAobGV0IHN1YkNQIG9mIHRoaXMuZGVmYXVsdExpc3RJdGVtKVxuXHRcdFx0XHRjbG9uZWREZWZhdWx0TGlzdEl0ZW1zLnB1c2goc3ViQ1AuY2xvbmUoY2xvbmVWYWx1ZSkpO1xuXG5cdFx0XHRjcC5kZWZhdWx0TGlzdEl0ZW0gPSBjbG9uZWREZWZhdWx0TGlzdEl0ZW1zO1xuXHRcdH1cblxuXHRcdGNwLmxpc3RWYWx1ZXMgPSB0aGlzLmxpc3RWYWx1ZXM7IC8vIE5vIG5lZWQgdG8gY2xvbmUgdGhpcywgYXMgdGhlIGxpc3RWYWx1ZXMgc2V0dGVyIGFscmVhZHkgZG9lcyBpdFxuXHRcdGNwLmNsYXp6ID0gdGhpcy5jbGF6ejtcblx0XHRjcC5kZW55RW1wdHkgPSB0aGlzLmRlbnlFbXB0eTtcblxuXHRcdHJldHVybiBjcDtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZXNldCBpbml0aWFsIHZhbHVlIGJ5IGNvcHlpbmcgdGhlIGN1cnJlbnQgdmFsdWUuXG5cdCAqL1xuXHRyZXNldElzTW9kaWZpZWQoKVxuXHR7XG5cdFx0dGhpcy5faW5pdGlhbFZhbHVlID0gdGhpcy5fdmFsdWU7XG5cblx0XHQvLyBSZXNldCBzdWItcGFyYW1ldGVyc1xuXHRcdGlmICh0aGlzLl9saXN0SXRlbXMgIT0gbnVsbClcblx0XHR7XG5cdFx0XHRmb3IgKGxldCBsaXN0SXRlbSBvZiB0aGlzLl9saXN0SXRlbXMpXG5cdFx0XHR7XG5cdFx0XHRcdGZvciAobGV0IHN1YkNQIG9mIGxpc3RJdGVtKVxuXHRcdFx0XHRcdHN1YkNQLnJlc2V0SXNNb2RpZmllZCgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuX2xpc3RJdGVtc0NoYW5nZWQgPSBmYWxzZTtcblx0fVxuXG5cdGFkZExpc3RJdGVtKG5ld0xpc3RJdGVtKVxuXHR7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zLnB1c2gobmV3TGlzdEl0ZW0pO1xuXHRcdHRoaXMuX2xpc3RJdGVtc0NoYW5nZWQgPSB0cnVlO1xuXHR9XG5cblx0dXBkYXRlTGlzdEl0ZW0obGlzdEl0ZW0sIGl0ZW1JbmRleClcblx0e1xuXHRcdHRoaXMuX2xpc3RJdGVtc1tpdGVtSW5kZXhdID0gbGlzdEl0ZW07XG5cdFx0dGhpcy5fbGlzdEl0ZW1zQ2hhbmdlZCA9IHRydWU7XG5cdH1cblxuXHRyZW1vdmVMaXN0SXRlbShpdGVtSW5kZXgpXG5cdHtcblx0XHR0aGlzLl9saXN0SXRlbXMuc3BsaWNlKGl0ZW1JbmRleCwgMSk7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zQ2hhbmdlZCA9IHRydWU7XG5cdH1cblxuXHR0b1Nmc09iamVjdCgpXG5cdHtcblx0XHRsZXQgb2JqID0gbmV3IFNGUzJYLlNGU09iamVjdCgpO1xuXG5cdFx0Ly8gU2V0IGNoYW5nZWQgc2V0dGluZyBuYW1lXG5cdFx0b2JqLnB1dFV0ZlN0cmluZygnbmFtZScsIHRoaXMubmFtZSk7XG5cblx0XHQvLyBTZXQgY2hhbmdlZCBzZXR0aW5nIGNsYXNzLCBpZiBhbnlcblx0XHRpZiAodGhpcy5jbGF6eiAhPSBudWxsKVxuXHRcdFx0b2JqLnB1dFV0ZlN0cmluZygnY2xhenonLCB0aGlzLmNsYXp6KTtcblxuXHRcdGlmICh0aGlzLnZhbHVlICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IGNoYW5nZWQgc2V0dGluZyB2YWx1ZVxuXHRcdFx0aWYgKHR5cGVvZiB0aGlzLnZhbHVlID09PSAnYm9vbGVhbicpXG5cdFx0XHRcdG9iai5wdXRCb29sKCd2YWx1ZScsIHRoaXMudmFsdWUpO1xuXHRcdFx0ZWxzZSBpZiAodHlwZW9mIHRoaXMudmFsdWUgPT09ICdudW1iZXInKVxuXHRcdFx0XHRvYmoucHV0SW50KCd2YWx1ZScsIHRoaXMudmFsdWUpO1xuXHRcdFx0ZWxzZVxuXHRcdFx0XHRvYmoucHV0VGV4dCgndmFsdWUnLCB0aGlzLnZhbHVlKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdC8vIFNldCBjaGFuZ2VkIHNldHRpbmcgbGlzdCBvZiB2YWx1ZXNcblxuXHRcdFx0bGV0IGxpc3RJdGVtcyA9IG5ldyBTRlMyWC5TRlNBcnJheSgpO1xuXG5cdFx0XHRmb3IgKGxldCBhIG9mIHRoaXMuX2xpc3RJdGVtcylcblx0XHRcdHtcblx0XHRcdFx0aWYgKGEubGVuZ3RoID09IDEpIC8vIFdlIGhhdmUganVzdCBvbmUgc3ViIGNvbmZpZyBwYXJhbTsgbm8gbmVlZCB0byBwYXJzZSBpdCBjb21wbGl0ZWx5XG5cdFx0XHRcdHtcblx0XHRcdFx0XHQvLyBTaW1wbGUgbGlzdFxuXHRcdFx0XHRcdGxldCB0ZW1wT2JqID0gYVswXS50b1Nmc09iamVjdCgpO1xuXHRcdFx0XHRcdGxldCB3YSA9IHRlbXBPYmouZ2V0V3JhcHBlZEl0ZW0oJ3ZhbHVlJyk7XG5cdFx0XHRcdFx0bGlzdEl0ZW1zLmFkZCh3YS52YWx1ZSwgd2EudHlwZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0Ly8gQ29tcGxleCBsaXN0XG5cblx0XHRcdFx0XHRsZXQgdmFsdWVzID0gbmV3IFNGUzJYLlNGU0FycmF5KCk7XG5cblx0XHRcdFx0XHRmb3IgKGxldCBzdWJDcCBvZiBhKVxuXHRcdFx0XHRcdFx0dmFsdWVzLmFkZFNGU09iamVjdChzdWJDcC50b1Nmc09iamVjdCgpKTtcblxuXHRcdFx0XHRcdGxpc3RJdGVtcy5hZGRTRlNBcnJheSh2YWx1ZXMpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdG9iai5wdXRTRlNBcnJheSgndmFsdWUnLCBsaXN0SXRlbXMpO1xuXHRcdH1cblxuXHRcdHJldHVybiBvYmo7XG5cdH1cblxuXHQvKipcblx0ICogUmV0dXJuIGEgZGVzY3JpcHRpb24gb2YgdGhlIENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIgaW5zdGFuY2UuXG5cdCAqL1xuXHR0b1N0cmluZygpXG5cdHtcblx0XHRsZXQgcyA9IGBgO1xuXHRcdHMgKz0gYENvbmZpZ3VyYXRpb24gcGFyYW1ldGVyOiAke3RoaXMubmFtZX1cXG5gO1xuXHRcdHMgKz0gYFxcdHR5cGU6ICR7dGhpcy50eXBlfVxcbmA7XG5cdFx0cyArPSBgXFx0bGFiZWw6ICR7dGhpcy5sYWJlbH1cXG5gO1xuXHRcdHMgKz0gYFxcdGNhdGVnb3J5IG5hbWU6ICR7dGhpcy5jYXRlZ29yeX1cXG5gO1xuXHRcdHMgKz0gYFxcdGNhdGVnb3J5IGlkOiAke3RoaXMuY2F0ZWdvcnlJZH1cXG5gO1xuXHRcdHMgKz0gYFxcdHRvb2x0aXA6ICR7dGhpcy50b29sdGlwfVxcbmA7XG5cdFx0cyArPSBgXFx0dmFsdWU6ICR7dGhpcy52YWx1ZX1cXG5gO1xuXHRcdHMgKz0gYFxcdHRyaWdnZXI6ICR7dGhpcy50cmlnZ2VyfVxcbmA7XG5cdFx0cyArPSBgXFx0dHJpZ2dlciBkYXRhOiAke3RoaXMudHJpZ2dlckRhdGF9XFxuYDtcblx0XHRzICs9IGBcXHRjbGllbnQgb25seTogJHt0aGlzLmNsaWVudE9ubHl9XFxuYDtcblx0XHRzICs9IGBcXHR2YWxpZGF0b3I6ICR7dGhpcy52YWxpZGF0b3J9XFxuYDtcblx0XHRzICs9IGBcXHRpcyBtb2RpZmllZDogJHt0aGlzLmlzTW9kaWZpZWR9XFxuYDtcblxuXHRcdGlmICh0aGlzLmF0dHJpYnV0ZXMgIT0gbnVsbClcblx0XHR7XG5cdFx0XHRzICs9IGBcXHRjb21wb25lbnQgYXR0cmlidXRlczpcXG5gO1xuXG5cdFx0XHRmb3IgKGxldCBzMSBpbiB0aGlzLmF0dHJpYnV0ZXMpXG5cdFx0XHRcdHMgKz0gYFxcdFxcdCR7czF9IC0tPiAke3RoaXMuYXR0cmlidXRlc1tzMV19XFxuYDtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5kYXRhUHJvdmlkZXIgIT0gbnVsbClcblx0XHRcdHMgKz0gYFxcdGRhdGEgcHJvdmlkZXI6ICR7dGhpcy5kYXRhUHJvdmlkZXJ9XFxuYDtcblxuXHRcdGlmICh0aGlzLnNlcGFyYXRvciAhPSBudWxsKVxuXHRcdHtcblx0XHRcdHMgKz0gYFxcdHNlcGFyYXRvcjpcXG5gO1xuXG5cdFx0XHRmb3IgKGxldCBzMiBpbiB0aGlzLnNlcGFyYXRvcilcblx0XHRcdFx0cyArPSBgXFx0XFx0JHtzMn0gLS0+ICR7dGhpcy5zZXBhcmF0b3JbczJdfVxcbmA7XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuX2xpc3RJdGVtcyAhPSBudWxsICYmIHRoaXMuX2xpc3RJdGVtcy5sZW5ndGggPiAwKVxuXHRcdHtcblx0XHRcdHMgKz0gYFxcdCMgbGlzdCBpdGVtczogJHt0aGlzLl9saXN0SXRlbXMubGVuZ3RofVxcbmA7XG5cblx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5fbGlzdEl0ZW1zLmxlbmd0aDsgaSsrKVxuXHRcdFx0e1xuXHRcdFx0XHRzICs9IGBcXHRsaXN0IGl0ZW0gJHtpfSBzdWItcGFyYW1ldGVyczpcXG5gO1xuXHRcdFx0XHRmb3IgKGxldCBlID0gMDsgZSA8IHRoaXMuX2xpc3RJdGVtc1tpXS5sZW5ndGg7IGUrKylcblx0XHRcdFx0XHRzICs9IGBcXHRcXHQke3RoaXMuX2xpc3RJdGVtc1tpXVtlXS50b0NvbXBhY3RTdHJpbmcoKX1cXG5gO1xuXHRcdFx0fVxuXG5cdFx0XHRzICs9IGBcXHRjbGFzcyBuYW1lOiAke3RoaXMuY2xhenp9XFxuYDtcblx0XHRcdHMgKz0gYFxcdGRlbnkgZW1wdHkgbGlzdDogJHt0aGlzLmRlbnlFbXB0eX1cXG5gO1xuXHRcdH1cblxuXHRcdHJldHVybiBzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybiBhIGNvbXBhY3QgZGVzY3JpcHRpb24gb2YgdGhlIENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIgaW5zdGFuY2UuXG5cdCAqL1xuXHR0b0NvbXBhY3RTdHJpbmcoKVxuXHR7XG5cdFx0cmV0dXJuIGBDb25maWd1cmF0aW9uIHBhcmFtZXRlciAnJHt0aGlzLm5hbWV9JzogJHt0aGlzLnZhbHVlfSAke3RoaXMuaXNNb2RpZmllZCA/ICdbWF0nIDogJ1sgXSd9YDtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFBSSVZBVEUgTUVUSE9EU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdC8qKlxuXHQgKiBSZXRyaWV2ZSB0aGUgY2F0ZWdvcnkgaWQgZm9ybSB0aGUgY2F0ZWdvcnkgbmFtZS5cblx0ICogU3BhY2VzIGFuZCBpbnZhbGlkIGNoYXJhY3RlcnMgYXJlIHJlbW92ZWQ7IHdvcmRzIGFyZSBzZXBhcmF0ZWQgdXNpbmcgY2FwaXRhbHMuXG5cdCAqL1xuXHRfc2V0SWRGcm9tQ2F0ZWdvcnlOYW1lKGNhdGVnb3J5TmFtZSlcblx0e1xuXHRcdHRoaXMuX2NhdGVnb3J5SWQgPSBjYXRlZ29yeU5hbWU7XG5cblx0XHQvLyBTdHJpcCBpbnZhbGlkIGNoYXJhY3RlcnNcblx0XHR2YXIgcGF0dGVybiA9IC9bXjAtOWEtekEtWl0vZztcblx0XHR0aGlzLl9jYXRlZ29yeUlkID0gdGhpcy5fY2F0ZWdvcnlJZC5yZXBsYWNlKHBhdHRlcm4sICcgJyk7XG5cblx0XHQvLyBDYXBpdGFsaXplIHdvcmRzXG5cdFx0dmFyIHdvcmRzID0gdGhpcy5fY2F0ZWdvcnlJZC5zcGxpdCgnICcpO1xuXHRcdHRoaXMuX2NhdGVnb3J5SWQgPSAnJztcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgd29yZHMubGVuZ3RoOyBpKyspXG5cdFx0e1xuXHRcdFx0bGV0IHdvcmQgPSB3b3Jkc1tpXTtcblx0XHRcdGlmICh3b3JkLmxlbmd0aCA+IDApXG5cdFx0XHRcdHRoaXMuX2NhdGVnb3J5SWQgKz0gKGkgPiAwID8gd29yZC5zdWJzdHIoMCwxKS50b1VwcGVyQ2FzZSgpIDogd29yZC5zdWJzdHIoMCwxKS50b0xvd2VyQ2FzZSgpKSArICh3b3JkLmxlbmd0aCA+IDEgPyB3b3JkLnN1YnN0cigxKSA6IFwiXCIpO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLl9jYXRlZ29yeUlkLmxlbmd0aCA9PSAwKVxuXHRcdFx0dGhpcy5fY2F0ZWdvcnlJZCA9IHRoaXMuREVGQVVMVF9DQVRFR09SWV9JRDtcblx0fVxuXG5cdF9zZXRTdWJDb25maWd1cmF0aW9uUGFyYW1zKF9saXN0VmFsdWVzKVxuXHR7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zID0gW107XG5cblx0XHRmb3IgKGxldCBvYmogb2YgX2xpc3RWYWx1ZXMpXG5cdFx0e1xuXHRcdFx0bGV0IGxpc3RJdGVtID0gW107XG5cblx0XHRcdGZvciAobGV0IGRlZmF1bHRDUCBvZiB0aGlzLmRlZmF1bHRMaXN0SXRlbSlcblx0XHRcdHtcblx0XHRcdFx0bGV0IHN1YkNQID0gZGVmYXVsdENQLmNsb25lKGZhbHNlKTtcblx0XHRcdFx0c3ViQ1AudmFsdWUgPSBvYmpbc3ViQ1AubmFtZV07XG5cblx0XHRcdFx0bGlzdEl0ZW0ucHVzaChzdWJDUCk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2xpc3RJdGVtcy5wdXNoKGxpc3RJdGVtKTtcblx0XHR9XG5cdH1cblxuXHRfZ2V0U3ViQ29uZmlndXJhdGlvblBhcmFtc1ZhbHVlcygpXG5cdHtcblx0XHRsZXQgX2xpc3RWYWx1ZXMgPSBbXTtcblxuXHRcdGZvciAobGV0IGxpc3RJdGVtIG9mIHRoaXMuX2xpc3RJdGVtcylcblx0XHR7XG5cdFx0XHRsZXQgb2JqID0ge307XG5cblx0XHRcdGZvciAobGV0IHN1YkNQIG9mIGxpc3RJdGVtKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoc3ViQ1AudmFsdWUgIT0gbnVsbClcblx0XHRcdFx0XHRvYmpbc3ViQ1AubmFtZV0gPSBzdWJDUC52YWx1ZTtcblx0XHRcdH1cblxuXHRcdFx0X2xpc3RWYWx1ZXMucHVzaChvYmopO1xuXHRcdH1cblxuXHRcdHJldHVybiBfbGlzdFZhbHVlcztcblx0fVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDNUdBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDeEhBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQ3pMQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUN4T0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDbFhBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzNCQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQy9HQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUN6RkE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUM3RUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQzdFQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUM3SkE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ2hEQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUM3UUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0EiLCJzb3VyY2VSb290IjoiIn0=