rubyfox-server 2.17.3.1 → 2.19.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rubyfox/server/data/config/admin/descriptors/config_room.txt +10 -1
  3. data/lib/rubyfox/server/data/config/admin/descriptors/config_server.txt +90 -20
  4. data/lib/rubyfox/server/data/config/admin/descriptors/config_zone.txt +9 -0
  5. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_room.txt +11 -0
  6. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_user.txt +3 -3
  7. data/lib/rubyfox/server/data/config/core.xml +4 -4
  8. data/lib/rubyfox/server/data/config/default.words.txt +11 -0
  9. data/lib/rubyfox/server/data/config/log4j.properties +1 -2
  10. data/lib/rubyfox/server/data/config/server.xml +1 -1
  11. data/lib/rubyfox/server/data/data/GeoLite2-Country.mmdb +0 -0
  12. data/lib/rubyfox/server/data/data/bannedusers/users.bin +0 -0
  13. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/bootstrap.jar +0 -0
  14. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/catalina-tasks.xml +39 -39
  15. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/catalina.sh +0 -0
  16. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/ciphers.sh +0 -0
  17. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/commons-daemon-native.tar.gz +0 -0
  18. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/commons-daemon.jar +0 -0
  19. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/configtest.sh +0 -0
  20. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/daemon.sh +0 -0
  21. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/digest.sh +0 -0
  22. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/makebase.sh +0 -0
  23. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/setclasspath.sh +0 -0
  24. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/shutdown.sh +0 -0
  25. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/startup.sh +0 -0
  26. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tomcat-juli.jar +0 -0
  27. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tomcat-native.tar.gz +0 -0
  28. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tool-wrapper.sh +0 -0
  29. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/version.sh +0 -0
  30. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/Catalina/localhost/rewrite.config +1 -1
  31. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/catalina.policy +263 -264
  32. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/catalina.properties +209 -207
  33. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/context.xml +31 -31
  34. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/jaspic-providers.xml +23 -23
  35. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/jaspic-providers.xsd +52 -52
  36. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/keystore.jks +0 -0
  37. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/server.xml +177 -161
  38. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/tomcat-users.xml +18 -7
  39. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/tomcat-users.xsd +59 -59
  40. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/web.xml +4740 -4737
  41. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/annotations-api.jar +0 -0
  42. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ant.jar +0 -0
  43. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ha.jar +0 -0
  44. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ssi.jar +0 -0
  45. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-storeconfig.jar +0 -0
  46. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-tribes.jar +0 -0
  47. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina.jar +0 -0
  48. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/el-api.jar +0 -0
  49. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jasper-el.jar +0 -0
  50. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jasper.jar +0 -0
  51. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jaspic-api.jar +0 -0
  52. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jsp-api.jar +0 -0
  53. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/servlet-api.jar +0 -0
  54. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/sfs2x-ws-helper.jar +0 -0
  55. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-api.jar +0 -0
  56. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-coyote.jar +0 -0
  57. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-dbcp.jar +0 -0
  58. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-cs.jar +0 -0
  59. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-de.jar +0 -0
  60. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-es.jar +0 -0
  61. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-fr.jar +0 -0
  62. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ja.jar +0 -0
  63. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ko.jar +0 -0
  64. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-pt-BR.jar +0 -0
  65. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ru.jar +0 -0
  66. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-zh-CN.jar +0 -0
  67. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-jdbc.jar +0 -0
  68. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-jni.jar +0 -0
  69. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-util-scan.jar +0 -0
  70. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-util.jar +0 -0
  71. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-websocket.jar +0 -0
  72. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/websocket-api.jar +0 -0
  73. data/lib/rubyfox/server/data/lib/javax.activation-1.2.0.jar +0 -0
  74. data/lib/rubyfox/server/data/lib/javax.mail.jar +0 -0
  75. data/lib/rubyfox/server/data/lib/js/JSApi.js +2 -1
  76. data/lib/rubyfox/server/data/lib/js/LibApi.js +181 -48
  77. data/lib/rubyfox/server/data/lib/sfs2x-admin.jar +0 -0
  78. data/lib/rubyfox/server/data/lib/sfs2x-cluster.jar +0 -0
  79. data/lib/rubyfox/server/data/lib/sfs2x-core.jar +0 -0
  80. data/lib/rubyfox/server/data/lib/sfs2x.jar +0 -0
  81. data/lib/rubyfox/server/data/sfs2x-service +26 -30
  82. data/lib/rubyfox/server/data/www/BlueBox.war +0 -0
  83. data/lib/rubyfox/server/data/www/HelloServlet/WEB-INF/web.xml +1 -3
  84. data/lib/rubyfox/server/data/www/ROOT/_css_/default.css +14 -6
  85. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/style.css +44 -2
  86. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/application.bundle.js +98 -61
  87. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/endors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-6~mod-7~mod-8~mod-9.bundle.js +17357 -0
  88. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-0.bundle.js +4 -4
  89. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-1.bundle.js +3 -3
  90. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-10.bundle.js +101 -66
  91. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-11.bundle.js +544 -8
  92. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12.bundle.js +915 -1480
  93. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12~module-15~module-16~module-4.bundle.js +2665 -0
  94. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-13.bundle.js +606 -3093
  95. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-13~module-16~module-17~module-4.bundle.js +2665 -0
  96. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-14.bundle.js +764 -0
  97. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-15.bundle.js +71 -0
  98. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-16.bundle.js +1787 -0
  99. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-17.bundle.js +3383 -0
  100. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-4.bundle.js +121 -1009
  101. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-5.bundle.js +1214 -1744
  102. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-6.bundle.js +398 -666
  103. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-7.bundle.js +717 -192
  104. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-8.bundle.js +2117 -665
  105. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-9.bundle.js +613 -690
  106. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~mod-0~mod-1~mod-10~mod-11~mod-16~mod-5~mod-6~mod-7~mod-8.bundle.js +17357 -0
  107. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-5~mod-6~mod-7~mod-8~mod-9.bundle.js +17357 -0
  108. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/{vendors~module-0~module-1~module-13~module-4~module-5~module-7~module-8.bundle.js → vendors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-5~mod-7~mod-8~mod-9.bundle.js} +2 -2
  109. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-12.bundle.js +807 -0
  110. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-13.bundle.js +807 -0
  111. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-configurator.html +32 -0
  112. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-monitor.html +185 -0
  113. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-updater.html +47 -0
  114. data/lib/rubyfox/server/data/www/ROOT/admin/modules/extension-deployer.html +84 -0
  115. data/lib/rubyfox/server/data/www/ROOT/admin/modules/zone-monitor.html +15 -8
  116. data/lib/rubyfox/server/data/www/ROOT/index.html +13 -23
  117. data/lib/rubyfox/server/data/www/host-manager/META-INF/context.xml +2 -2
  118. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/jsp/404.jsp +2 -2
  119. data/lib/rubyfox/server/data/www/host-manager/{manager.xml → WEB-INF/manager.xml} +5 -1
  120. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/web.xml +17 -0
  121. data/lib/rubyfox/server/data/www/host-manager/css/manager.css +141 -0
  122. data/lib/rubyfox/server/data/www/host-manager/images/tomcat.svg +967 -0
  123. data/lib/rubyfox/server/data/www/manager/META-INF/context.xml +2 -0
  124. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorCerts.jsp +1 -1
  125. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorCiphers.jsp +1 -1
  126. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorTrustedCerts.jsp +1 -1
  127. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/sessionDetail.jsp +3 -3
  128. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/sessionsList.jsp +1 -1
  129. data/lib/rubyfox/server/data/www/manager/WEB-INF/web.xml +17 -0
  130. data/lib/rubyfox/server/data/www/manager/css/manager.css +141 -0
  131. data/lib/rubyfox/server/data/www/manager/images/tomcat.svg +967 -0
  132. data/lib/rubyfox/server/data/www/manager/xform.xsl +74 -59
  133. data/lib/rubyfox/server/version.rb +1 -1
  134. metadata +30 -31
  135. data/lib/rubyfox/server/data/config/admin/icons/Analytics.png +0 -0
  136. data/lib/rubyfox/server/data/config/admin/icons/BanManager.png +0 -0
  137. data/lib/rubyfox/server/data/config/admin/icons/BlueBoxMonitor.png +0 -0
  138. data/lib/rubyfox/server/data/config/admin/icons/Console.png +0 -0
  139. data/lib/rubyfox/server/data/config/admin/icons/Dashboard.png +0 -0
  140. data/lib/rubyfox/server/data/config/admin/icons/ExtensionManager.png +0 -0
  141. data/lib/rubyfox/server/data/config/admin/icons/LicenseManager.png +0 -0
  142. data/lib/rubyfox/server/data/config/admin/icons/LogViewer.png +0 -0
  143. data/lib/rubyfox/server/data/config/admin/icons/ServerConfigurator.png +0 -0
  144. data/lib/rubyfox/server/data/config/admin/icons/ServletManager.png +0 -0
  145. data/lib/rubyfox/server/data/config/admin/icons/ZoneConfigurator.png +0 -0
  146. data/lib/rubyfox/server/data/config/admin/icons/ZoneMonitor.png +0 -0
  147. data/lib/rubyfox/server/data/lib/BlueBox.war +0 -0
  148. data/lib/rubyfox/server/data/lib/apache-tomcat/LICENSE +0 -1061
  149. data/lib/rubyfox/server/data/lib/apache-tomcat/NOTICE +0 -68
  150. data/lib/rubyfox/server/data/lib/apache-tomcat/README.md +0 -81
  151. data/lib/rubyfox/server/data/lib/apache-tomcat/RELEASE-NOTES +0 -174
  152. data/lib/rubyfox/server/data/lib/imap.jar +0 -0
  153. data/lib/rubyfox/server/data/lib/mailapi.jar +0 -0
  154. data/lib/rubyfox/server/data/lib/pop3.jar +0 -0
  155. data/lib/rubyfox/server/data/lib/smtp.jar +0 -0
  156. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12~module-13~module-9.bundle.js +0 -2634
  157. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-9.bundle.js +0 -807
  158. data/lib/rubyfox/server/data/www/host-manager/images/tomcat.gif +0 -0
  159. data/lib/rubyfox/server/data/www/manager/images/tomcat.gif +0 -0
  160. /data/lib/rubyfox/server/data/data/buddylists/{BasicExamples/.keep → .keep} +0 -0
@@ -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=