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
@@ -287,149 +287,11 @@ webpackContext.id = "./node_modules/moment/locale sync recursive ^\\.\\/.*$";
287
287
 
288
288
  /***/ }),
289
289
 
290
- /***/ "./src/components/charts/base-chart.js":
291
- /*!*********************************************!*\
292
- !*** ./src/components/charts/base-chart.js ***!
293
- \*********************************************/
294
- /*! exports provided: BaseChart */
295
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
296
-
297
- "use strict";
298
- __webpack_require__.r(__webpack_exports__);
299
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseChart", function() { return BaseChart; });
300
- class BaseChart extends HTMLElement
301
- {
302
- constructor(maxValues)
303
- {
304
- super();
305
-
306
- this._maxValues = maxValues;
307
-
308
- // Initialize
309
- this._initialize();
310
- }
311
-
312
- // Can be overridden
313
- _initialize()
314
- {
315
- // Create chart html
316
- let chartHtml = $('<div>');
317
- $(this).append(chartHtml);
318
-
319
- this._chartWidget = this._initChartWidget(chartHtml);
320
-
321
- // Reset data source
322
- this.reset();
323
- }
324
-
325
- // MUST BE OVERRIDDEN
326
- _initChartWidget()
327
- {
328
- throw new Error('Chart widget must be initialized!')
329
- }
330
-
331
- set paused(value)
332
- {
333
- this.isPaused = value;
334
- this._onPauseChange();
335
- }
336
-
337
- get paused()
338
- {
339
- return this.isPaused;
340
- }
341
-
342
- reset()
343
- {
344
- this._chartWidget.setDataSource([]);
345
- }
346
-
347
- redraw()
348
- {
349
- this._chartWidget.redraw();
350
- }
351
-
352
- getLastEntry()
353
- {
354
- let ds;
355
-
356
- if (this.isPaused)
357
- ds = this._tempDS;
358
- else
359
- ds = this._dataSource;
360
-
361
- if (ds != null && ds.total() > 0)
362
- return ds.at(ds.total() - 1);
363
- else
364
- return null;
365
- }
366
-
367
- _addEntry(newEntry)
368
- {
369
- if (this.isPaused)
370
- {
371
- if (this._tempDS == null)
372
- this._tempDS = new kendo.data.DataSource();
373
-
374
- // Store new value in a temporary array
375
- this._tempDS.add(newEntry);
376
- }
377
- else
378
- {
379
- let ds = this._dataSource;
380
-
381
- if (this._tempDS != null)
382
- {
383
- // Concatenate temporary entries to actual data source
384
- let newArr = $.merge(ds.data(), this._tempDS.data());
385
-
386
- // Remove values exceeding MAX_VALUES
387
- if (newArr.length > this._maxValues)
388
- newArr.splice(0, newArr.length - this._maxValues)
389
-
390
- // Create new datasource
391
- let newDS = new kendo.data.DataSource({data: newArr})
392
-
393
- // Assign new data source to chart
394
- this._chartWidget.setDataSource(newDS);
395
-
396
- // Remove temporary array
397
- this._tempDS = null;
398
- }
399
-
400
- // Add new entry
401
- ds.add(newEntry);
402
-
403
- // Remove first item if needed
404
- if (ds.total() > this._maxValues)
405
- ds.remove(ds.at(0));
406
- }
407
- }
408
-
409
- get _dataSource()
410
- {
411
- return this._chartWidget.dataSource;
412
- }
413
-
414
- _onPauseChange()
415
- {
416
- // Nothing to do, should be overridden
417
- }
418
- }
419
-
420
- // DEFINE COMPONENT
421
- if (!window.customElements.get('base-chart'))
422
- window.customElements.define('base-chart', BaseChart);
423
-
424
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
425
-
426
- /***/ }),
427
-
428
290
  /***/ "./src/components/charts/chart-utils.js":
429
291
  /*!**********************************************!*\
430
292
  !*** ./src/components/charts/chart-utils.js ***!
431
293
  \**********************************************/
432
- /*! exports provided: getFormattedDateTime, getBasicSharedTemplate, getMemorySharedTemplate, getMemoryValueAxisLabelTemplate, getNetworkSharedTemplate, getNetworkValueAxisLabelTemplate, getUserCountSharedTemplate, getTimeRangeTooltipTemplate, getWRBytesLabelTemplate */
294
+ /*! exports provided: getFormattedDateTime, getBasicSharedTemplate, getMemorySharedTemplate, getMemoryValueAxisLabelTemplate, getNetworkSharedTemplate, getNetworkValueAxisLabelTemplate, getNetworkValueAxisLabelTemplateB, getUserCountSharedTemplate, getTimeRangeTooltipTemplate, getWRBytesLabelTemplate, getBasicTemplate, getMemoryTemplate, getNetworkTemplate */
433
295
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
434
296
 
435
297
  "use strict";
@@ -440,9 +302,13 @@ __webpack_require__.r(__webpack_exports__);
440
302
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getMemoryValueAxisLabelTemplate", function() { return getMemoryValueAxisLabelTemplate; });
441
303
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNetworkSharedTemplate", function() { return getNetworkSharedTemplate; });
442
304
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNetworkValueAxisLabelTemplate", function() { return getNetworkValueAxisLabelTemplate; });
305
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNetworkValueAxisLabelTemplateB", function() { return getNetworkValueAxisLabelTemplateB; });
443
306
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getUserCountSharedTemplate", function() { return getUserCountSharedTemplate; });
444
307
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getTimeRangeTooltipTemplate", function() { return getTimeRangeTooltipTemplate; });
445
308
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getWRBytesLabelTemplate", function() { return getWRBytesLabelTemplate; });
309
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBasicTemplate", function() { return getBasicTemplate; });
310
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getMemoryTemplate", function() { return getMemoryTemplate; });
311
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNetworkTemplate", function() { return getNetworkTemplate; });
446
312
  /* harmony import */ var _utils_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../utils/utilities */ "./src/utils/utilities.js");
447
313
 
448
314
 
@@ -511,6 +377,15 @@ function getNetworkValueAxisLabelTemplate() {
511
377
  };
512
378
  }
513
379
 
380
+ function getNetworkValueAxisLabelTemplateB() {
381
+ return function(dataItem) {
382
+ dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
383
+ return kendo.template(`
384
+ #: bytesToSize(value, 1, '', '/s') #
385
+ `)(dataItem);
386
+ };
387
+ }
388
+
514
389
  function getUserCountSharedTemplate(categoryFormat = 'dd MMM HH:mm:ss') {
515
390
  return function(dataItem) {
516
391
  return kendo.template(`
@@ -555,82 +430,178 @@ function getWRBytesLabelTemplate() {
555
430
  };
556
431
  }
557
432
 
433
+ function getBasicTemplate(valueFormat = '{0}') {
434
+ return kendo.template(`
435
+ <div>
436
+ <span class="text-nowrap">#: kendo.toString(new Date(value.x), "dd/MM/yy HH:mm") #</span>
437
+ <br>
438
+ <strong class="text-nowrap">#: series.name #: #: kendo.format('${valueFormat}', value.y) # </strong>
439
+ </div>
440
+ `);
441
+ }
442
+
443
+ function getMemoryTemplate() {
444
+ return function(dataItem) {
445
+ dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
446
+ return kendo.template(`
447
+ <div>
448
+ <span class="text-nowrap">#: kendo.toString(new Date(value.x), "dd/MM/yy HH:mm") #</span>
449
+ <br>
450
+ <strong class="text-nowrap">#: series.name #: #: bytesToSize(value.y) # </strong>
451
+ </div>
452
+ `)(dataItem);
453
+ };
454
+ }
455
+
456
+ function getNetworkTemplate() {
457
+ return function(dataItem) {
458
+ dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
459
+ return kendo.template(`
460
+ <div>
461
+ <span class="text-nowrap">#: kendo.toString(new Date(value.x), "dd/MM/yy HH:mm") #</span>
462
+ <br>
463
+ <strong class="text-nowrap">#: series.name #: #: bytesToSize(value.y, 1, '', '/s') # </strong>
464
+ </div>
465
+ `)(dataItem);
466
+ };
467
+ }
468
+
558
469
 
559
470
  /***/ }),
560
471
 
561
- /***/ "./src/components/charts/cpu-usage-chart.js":
562
- /*!**************************************************!*\
563
- !*** ./src/components/charts/cpu-usage-chart.js ***!
564
- \**************************************************/
565
- /*! exports provided: CpuUsageChart */
472
+ /***/ "./src/components/module-specific/cluster-monitor/node-mini-charts.js":
473
+ /*!****************************************************************************!*\
474
+ !*** ./src/components/module-specific/cluster-monitor/node-mini-charts.js ***!
475
+ \****************************************************************************/
476
+ /*! exports provided: NodeMiniCharts */
566
477
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
567
478
 
568
479
  "use strict";
569
480
  __webpack_require__.r(__webpack_exports__);
570
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CpuUsageChart", function() { return CpuUsageChart; });
571
- /* harmony import */ var _base_chart__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-chart */ "./src/components/charts/base-chart.js");
572
- /* harmony import */ var _chart_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chart-utils */ "./src/components/charts/chart-utils.js");
481
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NodeMiniCharts", function() { return NodeMiniCharts; });
482
+ /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! moment */ "./node_modules/moment/moment.js");
483
+ /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_0__);
484
+ /* harmony import */ var _charts_chart_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../charts/chart-utils */ "./src/components/charts/chart-utils.js");
573
485
 
574
486
 
575
487
 
576
-
577
- class CpuUsageChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseChart"]
488
+ class NodeMiniCharts extends HTMLElement
578
489
  {
579
- constructor()
490
+ constructor(nodeId, nodeAlias, nodeName)
580
491
  {
581
- super(120);
582
- }
492
+ super();
583
493
 
584
- _initChartWidget(chartHtml)
585
- {
586
- return chartHtml.kendoChart({
494
+ const shadowRoot = this.attachShadow({mode: 'open'});
495
+ shadowRoot.innerHTML = `
496
+ <link rel="stylesheet" type="text/css" href="assets/css/custom-bootstrap.min.css" />
497
+ <link rel="stylesheet" type="text/css" href="assets/css/kendo.custom-bootstrap-v4.css" />
498
+
499
+ <style>
500
+ .box {
501
+ background-color: #FFF;
502
+ border-radius: .5rem;
503
+ }
504
+
505
+ .chart-container {
506
+ cursor: pointer;
507
+ }
508
+ </style>
509
+
510
+ <div class="container-fluid">
511
+ <div class="row py-3 box">
512
+ <div class="col-sm-6 col-md-4 col-lg-2 d-flex flex-column justify-content-center">
513
+ <small class="text-muted">Node</small>
514
+ <strong id="alias"></strong>
515
+ <small id="name"></small>
516
+ </div>
517
+ <div class="col-sm-6 col-md-4 col-lg-2 text-center chart-container" data-type="ccu">
518
+ <div class="chart"></div>
519
+ </div>
520
+ <div class="col-sm-6 col-md-4 col-lg-2 text-center chart-container" data-type="cpu">
521
+ <div class="chart"></div>
522
+ </div>
523
+ <div class="col-sm-6 col-md-4 col-lg-2 text-center chart-container" data-type="mem">
524
+ <div class="chart"></div>
525
+ </div>
526
+ <div class="col-sm-6 col-md-4 col-lg-2 text-center chart-container" data-type="net">
527
+ <div class="chart"></div>
528
+ </div>
529
+ <div class="col-sm-6 col-md-4 col-lg-2 text-center chart-container" data-type="thd">
530
+ <div class="chart"></div>
531
+ </div>
532
+ </div>
533
+ </div>
534
+ `;
535
+
536
+ this.nId = nodeId;
537
+ this.nAlias = nodeAlias;
538
+ this.nName = nodeName;
539
+
540
+ // Set tag's id attribute
541
+ this.id = 'node_' + nodeId;
542
+
543
+ if (nodeAlias)
544
+ {
545
+ $('#alias', shadowRoot).text(nodeAlias);
546
+ $('#name', shadowRoot).text(nodeName);
547
+ }
548
+ else
549
+ {
550
+ $('#alias', shadowRoot).text(nodeName);
551
+ $('#name', shadowRoot).hide();
552
+ }
553
+
554
+ this._getChartDiv('ccu').kendoChart({
587
555
  transitions: false,
588
556
  chartArea: {
589
- height: 120
557
+ height: 120,
558
+ background: 'transparent',
559
+ margin: 0,
560
+ padding:0
590
561
  },
591
562
  legend: {
592
563
  visible: false
593
564
  },
565
+ title: {
566
+ text: 'Concurrent Users',
567
+ font: '12px sans-serif',
568
+ color: '#212529'
569
+ },
594
570
  seriesDefaults: {
595
- type: 'area',
571
+ type: 'scatterLine',
596
572
  labels: {
597
573
  visible: false,
598
- format: '{0}%',
574
+ format: '{0}',
599
575
  background: 'transparent'
600
- }
576
+ },
577
+ missingValues: 'gap',
578
+ markers: {
579
+ visible: false,
580
+ type: 'circle',
581
+ size: 2,
582
+ },
583
+ width: 2
601
584
  },
602
585
  series: [
603
586
  {
604
- name: 'System',
605
- field: 'systemLoad',
606
- categoryField: 'time',
607
- color: this.systemColor,
608
- line: {
609
- width: 2
610
- }
611
- },
612
- {
613
- name: 'Process',
614
- field: 'processLoad',
615
- categoryField: 'time',
616
- color: this.processColor,
617
- line: {
618
- width: 2
619
- }
620
- }
587
+ xField: 'ts',
588
+ yField: 'val',
589
+ name: 'CCU',
590
+ color: '#3399FF'
591
+ }
621
592
  ],
622
- valueAxis: {
593
+ yAxis: {
623
594
  labels: {
624
- format: '{0}%'
595
+ format: '{0}',
596
+ step: 2
625
597
  },
626
598
  line: {
627
599
  visible: false
628
600
  },
629
- min: 0,
630
- max: 100
601
+ min: 0
631
602
  },
632
- categoryAxis: {
633
- majorGridLines: {
603
+ xAxis: {
604
+ majorGridLines: {
634
605
  visible: false
635
606
  },
636
607
  majorTicks: {
@@ -641,118 +612,63 @@ class CpuUsageChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseChart"
641
612
  }
642
613
  },
643
614
  tooltip: {
644
- shared: true,
645
- visible: true,
646
- sharedTemplate: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getBasicSharedTemplate"])('{0}%'),
615
+ visible: true,
616
+ template: Object(_charts_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getBasicTemplate"])('{0}'),
647
617
  background: '#e4e4e4'
648
618
  }
649
619
  }).data('kendoChart');
650
- }
651
-
652
- get systemColor()
653
- {
654
- return '#3399FF';
655
- }
656
-
657
- get processColor()
658
- {
659
- return '#0033CC';
660
- }
661
-
662
- addEntry(processLoad, systemLoad)
663
- {
664
- let newEntry = {
665
- time: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getFormattedDateTime"])(new Date()),
666
- processLoad: processLoad,
667
- systemLoad: systemLoad
668
- };
669
-
670
- // Add entry to chart
671
- super._addEntry(newEntry);
672
- }
673
- }
674
-
675
- // DEFINE COMPONENT
676
- if (!window.customElements.get('cpu-usage-chart'))
677
- window.customElements.define('cpu-usage-chart', CpuUsageChart);
678
-
679
-
680
- /***/ }),
681
-
682
- /***/ "./src/components/charts/memory-chart.js":
683
- /*!***********************************************!*\
684
- !*** ./src/components/charts/memory-chart.js ***!
685
- \***********************************************/
686
- /*! exports provided: MemoryChart */
687
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
688
-
689
- "use strict";
690
- __webpack_require__.r(__webpack_exports__);
691
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MemoryChart", function() { return MemoryChart; });
692
- /* harmony import */ var _base_chart__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-chart */ "./src/components/charts/base-chart.js");
693
- /* harmony import */ var _chart_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chart-utils */ "./src/components/charts/chart-utils.js");
694
-
695
-
696
-
697
-
698
- class MemoryChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseChart"]
699
- {
700
- constructor()
701
- {
702
- super(300);
703
620
 
704
- // Append text to display elapsed time
705
- this._elapsedTxt = $('<div>', {class: 'text-center', text: '---'});
706
- $(this).append(this._elapsedTxt);
707
- }
708
-
709
- _initChartWidget(chartHtml)
710
- {
711
- return chartHtml.kendoChart({
621
+ this._getChartDiv('cpu').kendoChart({
712
622
  transitions: false,
713
623
  chartArea: {
714
- height: 240
624
+ height: 120,
625
+ background: 'transparent',
626
+ margin: 0,
627
+ padding:0
715
628
  },
716
629
  legend: {
717
630
  visible: false
718
631
  },
632
+ title: {
633
+ text: 'CPU',
634
+ font: '12px sans-serif',
635
+ color: '#212529'
636
+ },
719
637
  seriesDefaults: {
720
- type: 'area',
638
+ type: 'scatterLine',
721
639
  labels: {
722
640
  visible: false,
723
- format: '{0}',
641
+ format: '{0}%',
724
642
  background: 'transparent'
725
643
  },
644
+ missingValues: 'gap',
645
+ markers: {
646
+ visible: false,
647
+ type: 'circle',
648
+ size: 3,
649
+ },
650
+ width: 2
726
651
  },
727
- series: [{
728
- name: 'Allocated',
729
- field: 'allocMem',
730
- categoryField: 'time',
731
- color: this.allocatedColor,
732
- line: {
733
- width: 2
734
- }
735
- },
736
- {
737
- name: 'Used',
738
- field: 'usedMem',
739
- categoryField: 'time',
740
- color: this.usedColor,
741
- line: {
742
- width: 2
743
- }
744
- }],
745
- valueAxis: {
652
+ series: [
653
+ {
654
+ xField: 'ts',
655
+ yField: 'val',
656
+ name: 'CPU',
657
+ color: '#3399FF'
658
+ }
659
+ ],
660
+ yAxis: {
746
661
  labels: {
747
- format: '{0}',
748
- template: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getMemoryValueAxisLabelTemplate"])()
662
+ format: '{0}%'
749
663
  },
750
664
  line: {
751
665
  visible: false
752
666
  },
753
- min: 0
667
+ min: 0,
668
+ max: 100,
669
+ majorUnit: 25
754
670
  },
755
- categoryAxis: {
671
+ xAxis: {
756
672
  majorGridLines: {
757
673
  visible: false
758
674
  },
@@ -763,390 +679,131 @@ class MemoryChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseChart"]
763
679
  visible: false
764
680
  }
765
681
  },
766
- tooltip: {
767
- shared: true,
768
- visible: true,
769
- sharedTemplate: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getMemorySharedTemplate"])(),
770
- background: '#e4e4e4'
682
+ tooltip: {
683
+ visible: true,
684
+ template: Object(_charts_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getBasicTemplate"])('{0}%'),
685
+ background: '#e4e4e4',
771
686
  }
772
687
  }).data('kendoChart');
773
- }
774
-
775
- get allocatedColor()
776
- {
777
- return '#3399FF';
778
- }
779
-
780
- get usedColor()
781
- {
782
- return '#0033CC';
783
- }
784
-
785
- addEntry(allocMem, usedMem)
786
- {
787
- let now = new Date();
788
-
789
- let newEntry = {
790
- time: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getFormattedDateTime"])(now),
791
- timestamp: now.getTime(),
792
- allocMem: allocMem,
793
- usedMem: usedMem
794
- };
795
-
796
- // Add entry to chart
797
- super._addEntry(newEntry);
798
-
799
- // Update x axis
800
- if (!this.isPaused)
801
- this._updateElapsedText();
802
- }
803
-
804
- _updateElapsedText()
805
- {
806
- let ds = this._dataSource;
807
-
808
- if (ds.total() > 1)
809
- {
810
- // Get axis limits
811
- const chartMinimum = ds.at(0).timestamp;
812
- const chartMaximum = ds.at(ds.total() - 1).timestamp;
813
-
814
- // Set elapsed text
815
- let seconds = Math.round( (chartMaximum - chartMinimum) / 1000 );
816
- let title;
817
-
818
- if (seconds < 60)
819
- title = 'Last ' + (seconds != 1 ? seconds + ' seconds' : 'second');
820
- else
821
- {
822
- const minutes = Math.floor(seconds / 60);
823
- title = 'Last ' + (minutes != 1 ? minutes + ' minutes' : 'minute');
824
- }
825
-
826
- this._elapsedTxt.text(title);
827
- }
828
- }
829
- }
830
-
831
- // DEFINE COMPONENT
832
- if (!window.customElements.get('memory-chart'))
833
- window.customElements.define('memory-chart', MemoryChart);
834
-
835
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
836
-
837
- /***/ }),
838
-
839
- /***/ "./src/components/charts/network-24h-chart.js":
840
- /*!****************************************************!*\
841
- !*** ./src/components/charts/network-24h-chart.js ***!
842
- \****************************************************/
843
- /*! exports provided: Network24hChart */
844
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
845
-
846
- "use strict";
847
- __webpack_require__.r(__webpack_exports__);
848
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Network24hChart", function() { return Network24hChart; });
849
- /* harmony import */ var _chart_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./chart-utils */ "./src/components/charts/chart-utils.js");
850
- /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! moment */ "./node_modules/moment/moment.js");
851
- /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_1__);
852
-
853
-
854
-
855
- class Network24hChart extends HTMLElement
856
- {
857
- constructor()
858
- {
859
- super();
860
-
861
- this._lastTotalOut = 0;
862
- this._lastTotalIn = 0;
863
- this._lastDate = new Date();
864
- this._samplingRateSeconds = 0;
865
-
866
- // Create chart html
867
- let chartHtml = $('<div>');
868
- $(this).append(chartHtml);
869
-
870
- // Initialize chart
871
- this._chartWidget = this._initChartWidget(chartHtml);
872
- }
873
688
 
874
- _initChartWidget(chartHtml)
875
- {
876
- return chartHtml.kendoChart({
689
+ this._getChartDiv('mem').kendoChart({
877
690
  transitions: false,
878
691
  chartArea: {
879
- height: 270,
880
- background: 'transparent'
692
+ height: 120,
693
+ background: 'transparent',
694
+ margin: 0,
695
+ padding:0
881
696
  },
882
697
  legend: {
883
698
  visible: false
884
699
  },
700
+ title: {
701
+ text: 'Memory',
702
+ font: '12px sans-serif',
703
+ color: '#212529'
704
+ },
885
705
  seriesDefaults: {
886
- type: 'area',
706
+ type: 'scatterLine',
887
707
  labels: {
888
708
  visible: false,
889
709
  format: '{0}',
890
710
  background: 'transparent'
891
711
  },
712
+ missingValues: 'gap',
713
+ markers: {
714
+ visible: false,
715
+ type: 'circle',
716
+ size: 3,
717
+ },
718
+ width: 2
892
719
  },
893
- series: [{
894
- name: 'Outgoing',
895
- field: 'outgoing',
896
- categoryField: 'time',
897
- color: '#CC0000',
898
- line: {
899
- width: 2
900
- }
901
- },
902
- {
903
- name: 'Incoming',
904
- field: 'incoming',
905
- categoryField: 'time',
906
- color: '#009900',
907
- line: {
908
- width: 2
909
- }
910
- }],
911
- valueAxis: {
720
+ series: [
721
+ {
722
+ xField: 'ts',
723
+ yField: 'val',
724
+ name: 'Memory',
725
+ color: '#3399FF'
726
+ }
727
+ ],
728
+ yAxis: {
912
729
  labels: {
913
730
  format: '{0}',
914
- template: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_0__["getNetworkValueAxisLabelTemplate"])()
731
+ template: Object(_charts_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getMemoryValueAxisLabelTemplate"])(),
732
+ step: 2
915
733
  },
916
734
  line: {
917
735
  visible: false
918
736
  },
919
- min: 0
737
+ min: 0,
920
738
  },
921
- categoryAxis: {
739
+ xAxis: {
922
740
  majorGridLines: {
923
- visible: true,
924
- step: 60
741
+ visible: false
925
742
  },
926
743
  majorTicks: {
927
- visible: true,
928
- step: 60
744
+ visible: false
929
745
  },
930
746
  labels: {
931
- visible: true,
932
- step: 60
933
- },
934
- baseUnit: 'minutes',
935
- type: 'date',
747
+ visible: false
748
+ }
936
749
  },
937
- tooltip: {
938
- shared: true,
939
- visible: true,
940
- sharedTemplate: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_0__["getNetworkSharedTemplate"])('dd MMM HH:mm'),
941
- background: '#e4e4e4'
750
+ tooltip: {
751
+ visible: true,
752
+ template: Object(_charts_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getMemoryTemplate"])(),
753
+ background: '#e4e4e4',
942
754
  }
943
755
  }).data('kendoChart');
944
- }
945
-
946
- redraw()
947
- {
948
- this._chartWidget.redraw();
949
- }
950
-
951
- set range(values)
952
- {
953
- this._range = values;
954
-
955
- this._updateXAxisLimits();
956
- }
957
-
958
- get range()
959
- {
960
- return this._range;
961
- }
962
-
963
- addHistoryEntries(outgoingData, incomingData, samplingRateSeconds, shiftSeconds)
964
- {
965
- this._samplingRateSeconds = samplingRateSeconds;
966
-
967
- let now = new Date();
968
-
969
- // NOTE: outgoingData and incominData are supposed to have the same size!!!
970
-
971
- if (outgoingData.length > 0)
972
- {
973
- let start = moment__WEBPACK_IMPORTED_MODULE_1__(now);
974
- start.subtract((samplingRateSeconds * outgoingData.length) + shiftSeconds, 's')
975
756
 
976
- this._lastTotalOut = outgoingData[0];
977
- this._lastTotalIn = incomingData[0];
978
- this._lastDate = start.toDate();
979
-
980
- if (outgoingData.length > 1)
981
- {
982
- let dataSource = new kendo.data.DataSource();
983
-
984
- for (let i = 1; i < outgoingData.length; i++)
985
- {
986
- const totalOut = outgoingData[i];
987
- const totalIn = incomingData[i];
988
-
989
- let date = start.clone();
990
- date.add(i * samplingRateSeconds, 's');
991
-
992
- this.addEntry(totalOut, totalIn, dataSource, date.toDate(), false);
993
- }
994
-
995
- // Assign datasource to chart
996
- this._chartWidget.setDataSource(dataSource);
997
-
998
- // Update axis
999
- this._updateXAxisLimits();
1000
- }
1001
- }
1002
- else
1003
- {
1004
- this._lastTotalOut = 0;
1005
- this._lastTotalIn = 0;
1006
- this._lastDate = now;
1007
- }
1008
- }
1009
-
1010
- addEntry(totalOut, totalIn, dataSource = null, date = null, updateAxis = true)
1011
- {
1012
- if (date == null)
1013
- date = new Date();
1014
-
1015
- const elapsedSecs = Math.round((date.getTime() - this._lastDate.getTime()) / 1000);
1016
-
1017
- // The 24h chart is updated at the same sampling rate used by the server to save the traffic history
1018
- if (elapsedSecs >= this._samplingRateSeconds)
1019
- {
1020
- let newEntry = {
1021
- time: date,
1022
- outgoing: Math.round((totalOut - this._lastTotalOut) / elapsedSecs),
1023
- incoming: Math.round((totalIn - this._lastTotalIn) / elapsedSecs)
1024
- };
1025
-
1026
- // Add entry to data source
1027
- if (dataSource == null)
1028
- dataSource = this._dataSource;
1029
-
1030
- dataSource.add(newEntry);
1031
-
1032
- this._lastTotalOut = totalOut;
1033
- this._lastTotalIn = totalIn;
1034
- this._lastDate = date;
1035
-
1036
- if (updateAxis)
1037
- this._updateXAxisLimits();
1038
- }
1039
- }
1040
-
1041
- _updateXAxisLimits()
1042
- {
1043
- let ds = this._dataSource;
1044
-
1045
- if (ds.total() > 0)
1046
- {
1047
- const chartMinimum = moment__WEBPACK_IMPORTED_MODULE_1__(this._lastDate).add(this._range[0], 'h');
1048
- const chartMaximum = moment__WEBPACK_IMPORTED_MODULE_1__(this._lastDate).add(this._range[1], 'h');
1049
-
1050
- this._chartWidget.options.categoryAxis.min = chartMinimum.toDate();
1051
- this._chartWidget.options.categoryAxis.max = chartMaximum.toDate();
1052
-
1053
- this._chartWidget.redraw();
1054
- }
1055
- }
1056
-
1057
- get _dataSource()
1058
- {
1059
- return this._chartWidget.dataSource;
1060
- }
1061
- }
1062
-
1063
- // DEFINE COMPONENT
1064
- if (!window.customElements.get('network-24h-chart'))
1065
- window.customElements.define('network-24h-chart', Network24hChart);
1066
-
1067
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1068
-
1069
- /***/ }),
1070
-
1071
- /***/ "./src/components/charts/network-realtime-chart.js":
1072
- /*!*********************************************************!*\
1073
- !*** ./src/components/charts/network-realtime-chart.js ***!
1074
- \*********************************************************/
1075
- /*! exports provided: NetworkRealtimeChart */
1076
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1077
-
1078
- "use strict";
1079
- __webpack_require__.r(__webpack_exports__);
1080
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NetworkRealtimeChart", function() { return NetworkRealtimeChart; });
1081
- /* harmony import */ var _base_chart__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-chart */ "./src/components/charts/base-chart.js");
1082
- /* harmony import */ var _chart_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chart-utils */ "./src/components/charts/chart-utils.js");
1083
-
1084
-
1085
-
1086
-
1087
- class NetworkRealtimeChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseChart"]
1088
- {
1089
- constructor()
1090
- {
1091
- super(300);
1092
-
1093
- this._lastTotalKbOut = 0;
1094
- this._lastTotalKbIn = 0;
1095
- this._lastTime = 0;
1096
-
1097
- // Append text to display elapsed time
1098
- this._elapsedTxt = $('<div>', {class: 'text-center', text: '---'});
1099
- $(this).append(this._elapsedTxt);
1100
- }
1101
-
1102
- _initChartWidget(chartHtml)
1103
- {
1104
- return chartHtml.kendoChart({
757
+ this._getChartDiv('thd').kendoChart({
1105
758
  transitions: false,
1106
759
  chartArea: {
1107
- height: 270,
1108
- background: 'transparent'
760
+ height: 120,
761
+ background: 'transparent',
762
+ margin: 0,
763
+ padding:0
1109
764
  },
1110
765
  legend: {
1111
766
  visible: false
1112
767
  },
768
+ title: {
769
+ text: 'Threads',
770
+ font: '12px sans-serif',
771
+ color: '#212529'
772
+ },
1113
773
  seriesDefaults: {
1114
- type: 'area',
774
+ type: 'scatterLine',
1115
775
  labels: {
1116
776
  visible: false,
1117
777
  format: '{0}',
1118
778
  background: 'transparent'
1119
779
  },
780
+ missingValues: 'gap',
781
+ markers: {
782
+ visible: false,
783
+ type: 'circle',
784
+ size: 3,
785
+ },
786
+ width: 2
1120
787
  },
1121
- series: [{
1122
- name: 'Outgoing',
1123
- field: 'outgoing',
1124
- categoryField: 'time',
1125
- color: this.outgoingColor,
1126
- line: {
1127
- width: 2
1128
- }
1129
- },
1130
- {
1131
- name: 'Incoming',
1132
- field: 'incoming',
1133
- categoryField: 'time',
1134
- color: this.incomingColor,
1135
- line: {
1136
- width: 2
1137
- }
1138
- }],
1139
- valueAxis: {
788
+ series: [
789
+ {
790
+ xField: 'ts',
791
+ yField: 'val',
792
+ name: 'Threads',
793
+ color: '#3399FF'
794
+ }
795
+ ],
796
+ yAxis: {
1140
797
  labels: {
1141
798
  format: '{0}',
1142
- template: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getNetworkValueAxisLabelTemplate"])()
799
+ step: 2
1143
800
  },
1144
801
  line: {
1145
802
  visible: false
1146
803
  },
1147
- min: 0,
804
+ min: 0
1148
805
  },
1149
- categoryAxis: {
806
+ xAxis: {
1150
807
  majorGridLines: {
1151
808
  visible: false
1152
809
  },
@@ -1157,209 +814,71 @@ class NetworkRealtimeChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["Bas
1157
814
  visible: false
1158
815
  }
1159
816
  },
1160
- tooltip: {
1161
- shared: true,
1162
- visible: true,
1163
- sharedTemplate: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getNetworkSharedTemplate"])(),
817
+ tooltip: {
818
+ visible: true,
819
+ template: Object(_charts_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getBasicTemplate"])('{0}'),
1164
820
  background: '#e4e4e4'
1165
821
  }
1166
822
  }).data('kendoChart');
1167
- }
1168
-
1169
- get outgoingColor()
1170
- {
1171
- return '#CC0000';
1172
- }
1173
-
1174
- get incomingColor()
1175
- {
1176
- return '#009900';
1177
- }
1178
-
1179
- addEntry(totalOutKb, totalInKb)
1180
- {
1181
- let now = new Date()
1182
- let time = now.getTime();
1183
-
1184
- // The first value sent by the server is not plotted: it would be a worng value because
1185
- // we have to calculate it as the difference between two total values, but we don't have the previous one
1186
- if (this._lastTime > 0)
1187
- {
1188
- let elapsedSecs = (time - this._lastTime) / 1000;
1189
-
1190
- const valueOut = Math.round((totalOutKb - this._lastTotalKbOut) / elapsedSecs);
1191
- const valueIn = Math.round((totalInKb - this._lastTotalKbIn) / elapsedSecs);
1192
-
1193
- let newEntry = {
1194
- time: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getFormattedDateTime"])(now),
1195
- timestamp: time,
1196
- outgoing: valueOut,
1197
- incoming: valueIn
1198
- };
1199
-
1200
- // Add entry to chart
1201
- super._addEntry(newEntry);
1202
-
1203
- // Update x axis
1204
- if (!this.isPaused)
1205
- this._updateElapsedText();
1206
- }
1207
-
1208
- this._lastTotalKbOut = totalOutKb;
1209
- this._lastTotalKbIn = totalInKb;
1210
- this._lastTime = time;
1211
- }
1212
-
1213
- _updateElapsedText()
1214
- {
1215
- let ds = this._dataSource;
1216
-
1217
- if (ds.total() > 1)
1218
- {
1219
- // Get axis limits
1220
- const chartMinimum = ds.at(0).timestamp;
1221
- const chartMaximum = ds.at(ds.total() - 1).timestamp;
1222
-
1223
- // Set elapsed text
1224
- let title;
1225
- let seconds = Math.round( (chartMaximum - chartMinimum) / 1000 );
1226
-
1227
- if (seconds < 60)
1228
- title = 'Last ' + (seconds != 1 ? seconds + ' seconds' : 'second');
1229
- else
1230
- {
1231
- const minutes = Math.floor(seconds / 60);
1232
- title = 'Last ' + (minutes != 1 ? minutes + ' minutes' : 'minute');
1233
- }
1234
-
1235
- this._elapsedTxt.text(title);
1236
- }
1237
- }
1238
- }
1239
-
1240
- // DEFINE COMPONENT
1241
- if (!window.customElements.get('network-realtime-chart'))
1242
- window.customElements.define('network-realtime-chart', NetworkRealtimeChart);
1243
-
1244
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1245
-
1246
- /***/ }),
1247
-
1248
- /***/ "./src/components/charts/system-queue-chart.js":
1249
- /*!*****************************************************!*\
1250
- !*** ./src/components/charts/system-queue-chart.js ***!
1251
- \*****************************************************/
1252
- /*! exports provided: SystemQueueChart */
1253
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1254
-
1255
- "use strict";
1256
- __webpack_require__.r(__webpack_exports__);
1257
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SystemQueueChart", function() { return SystemQueueChart; });
1258
- /* harmony import */ var _base_chart__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-chart */ "./src/components/charts/base-chart.js");
1259
- /* harmony import */ var _chart_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chart-utils */ "./src/components/charts/chart-utils.js");
1260
-
1261
-
1262
-
1263
-
1264
- class SystemQueueChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseChart"]
1265
- {
1266
- constructor()
1267
- {
1268
- super(240);
1269
-
1270
- this._averageLoad = 0;
1271
- }
1272
-
1273
- _initialize()
1274
- {
1275
- const chartHeight = 240;
1276
-
1277
- // Append container for chart & gauge
1278
- let container = $('<div>', {class: 'd-flex flex-row'});
1279
- $(this).append(container);
1280
-
1281
- // CHART
1282
-
1283
- let chartContainer = $('<div>', {class: 'flex-grow-1'});
1284
- container.append(chartContainer);
1285
-
1286
- // Create chart html
1287
- let chartHtml = $('<div>');
1288
- chartContainer.append(chartHtml);
1289
-
1290
- // Initialize chart
1291
- this._chartWidget = this._initChartWidget(chartHtml, chartHeight);
1292
-
1293
- // Append text to display elapsed time
1294
- this._elapsedTxt = $('<div>', {class: 'text-center', text: '---'});
1295
- chartContainer.append(this._elapsedTxt);
1296
-
1297
- // GAUGE
1298
-
1299
- let gaugeContainer = $('<div>');
1300
- container.append(gaugeContainer);
1301
-
1302
- // Create gauge html
1303
- let gaugeHtml = $('<div>');
1304
- gaugeContainer.append(gaugeHtml);
1305
823
 
1306
- // Initialize gauge
1307
- this._gaugeWidget = this._initGaugeWidget(gaugeHtml, chartHeight);
1308
-
1309
- // Append text to display load
1310
- this._loadTxt = $('<div>', {class: 'text-center font-weight-bold', text: '---'});
1311
- gaugeContainer.append(this._loadTxt);
1312
-
1313
- //------------------------------
1314
-
1315
- // Reset data source
1316
- this.reset();
1317
- }
1318
-
1319
- _initChartWidget(chartHtml, height)
1320
- {
1321
- return chartHtml.kendoChart({
824
+ this._getChartDiv('net').kendoChart({
1322
825
  transitions: false,
1323
826
  chartArea: {
1324
- height: height,
1325
- background: 'transparent'
827
+ height: 120,
828
+ background: 'transparent',
829
+ margin: 0,
830
+ padding:0
1326
831
  },
1327
832
  legend: {
1328
833
  visible: false
1329
834
  },
835
+ title: {
836
+ text: 'Network',
837
+ font: '12px sans-serif',
838
+ color: '#212529'
839
+ },
1330
840
  seriesDefaults: {
1331
- type: 'area',
841
+ type: 'scatterLine',
1332
842
  labels: {
1333
843
  visible: false,
1334
844
  format: '{0}',
1335
845
  background: 'transparent'
1336
- }
846
+ },
847
+ missingValues: 'gap',
848
+ markers: {
849
+ visible: false,
850
+ type: 'circle',
851
+ size: 3,
852
+ },
853
+ width: 2
1337
854
  },
1338
855
  series: [
1339
856
  {
1340
- name: 'Messages',
1341
- field: 'load',
1342
- categoryField: 'time',
1343
- color: '#3399ff',
1344
- line: {
1345
- width: 2
1346
- }
1347
- }
857
+ xField: 'ts',
858
+ yField: 'val',
859
+ name: 'Network Out',
860
+ color: '#CC0000',
861
+ },
862
+ {
863
+ xField: 'ts',
864
+ yField: 'val1',
865
+ name: 'Network In',
866
+ color: '#009900',
867
+ }
1348
868
  ],
1349
- valueAxis: {
1350
- title: {
1351
- text: 'Messages'
1352
- },
869
+ yAxis: {
1353
870
  labels: {
1354
- format: '{0}'
871
+ format: '{0}',
872
+ template: Object(_charts_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getNetworkValueAxisLabelTemplateB"])(),
873
+ step: 2
1355
874
  },
1356
875
  line: {
1357
876
  visible: false
1358
877
  },
1359
878
  min: 0
1360
879
  },
1361
- categoryAxis: {
1362
- majorGridLines: {
880
+ xAxis: {
881
+ majorGridLines: {
1363
882
  visible: false
1364
883
  },
1365
884
  majorTicks: {
@@ -1370,571 +889,186 @@ class SystemQueueChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseCha
1370
889
  }
1371
890
  },
1372
891
  tooltip: {
1373
- shared: true,
1374
- visible: true,
1375
- sharedTemplate: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getBasicSharedTemplate"])(),
892
+ visible: true,
893
+ template: Object(_charts_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getNetworkTemplate"])(),
1376
894
  background: '#e4e4e4'
1377
895
  }
1378
896
  }).data('kendoChart');
1379
- }
1380
-
1381
- _initGaugeWidget(gaugeHtml, height)
1382
- {
1383
- return gaugeHtml.kendoLinearGauge({
1384
- pointer: {
1385
- value: 0,
1386
- shape: 'arrow',
1387
- size: 10,
1388
- color: '#212529'
1389
- },
1390
- gaugeArea: {
1391
- height: height
1392
- },
1393
- scale: {
1394
- majorUnit: 10,
1395
- minorUnit: 1,
1396
- min: 0,
1397
- max: 100,
1398
- ranges: [
1399
- {
1400
- from: 0,
1401
- to: 50,
1402
- color: '#00cc00',
1403
- opacity: .5
1404
- }, {
1405
- from: 50,
1406
- to: 75,
1407
- color: '#ffe106',
1408
- opacity: .5
1409
- }, {
1410
- from: 75,
1411
- to: 100,
1412
- color: '#ed1601',
1413
- opacity: .5
1414
- }
1415
- ],
1416
- majorTicks: {
1417
- visible: true,
1418
- size: 10
1419
- },
1420
- minorTicks: {
1421
- visible: false
1422
- },
1423
- labels: {
1424
- visible: false
1425
- },
1426
- line: {
1427
- visible: false
1428
- },
1429
- rangeSize: 10
1430
- }
1431
- }).data('kendoLinearGauge');
1432
- }
1433
-
1434
- addEntry(load, queueMsgLimit)
1435
- {
1436
- // CHART
1437
-
1438
- let now = new Date();
1439
-
1440
- let newEntry = {
1441
- time: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getFormattedDateTime"])(now),
1442
- timestamp: now.getTime(),
1443
- load: load
1444
- };
1445
-
1446
- // Add entry to chart
1447
- super._addEntry(newEntry);
1448
-
1449
- // Update x axis
1450
- if (!this.isPaused)
1451
- this._updateElapsedText();
1452
897
 
1453
- // GAUGE
898
+ // Add chart container click listeners
899
+ $('.chart-container', this.shadowRoot).on('click', $.proxy(this._onChartContainerClick, this));
1454
900
 
1455
- // Evaluate average
1456
- let numValues = this._dataSource.total();
1457
-
1458
- if (numValues > 0)
1459
- {
1460
- let total = 0;
1461
- for (let i = 0; i < numValues; i++)
1462
- total += this._dataSource.at(i).load;
1463
-
1464
- this._averageLoad = Math.round(total / numValues);
1465
- }
1466
- else
1467
- this._averageLoad = 0;
1468
-
1469
- const avgLoadPerc = Math.round(this._averageLoad / queueMsgLimit * 1000) / 10;
1470
-
1471
- // Set gauge value
1472
- this._gaugeWidget.value(avgLoadPerc);
1473
-
1474
- // Set load text
1475
- this._loadTxt.text(avgLoadPerc + '%')
1476
- }
1477
-
1478
- _updateElapsedText()
1479
- {
1480
- let ds = this._dataSource;
1481
-
1482
- if (ds.total() > 1)
1483
- {
1484
- // Get axis limits
1485
- const chartMinimum = ds.at(0).timestamp;
1486
- const chartMaximum = ds.at(ds.total() - 1).timestamp;
1487
-
1488
- // Set elapsed text
1489
- let seconds = Math.round( (chartMaximum - chartMinimum) / 1000 );
1490
- let title;
1491
-
1492
- if (seconds < 60)
1493
- title = 'Last ' + (seconds != 1 ? seconds + ' seconds' : 'second');
1494
- else
1495
- {
1496
- const minutes = Math.floor(seconds / 60);
1497
- title = 'Last ' + (minutes != 1 ? minutes + ' minutes' : 'minute');
1498
- }
1499
-
1500
- this._elapsedTxt.text(title);
1501
- }
901
+ $(window).on('resize', $.proxy(this._onWindowResize, this));
902
+ this._onWindowResize();
1502
903
  }
1503
904
 
1504
- get load()
905
+ _onWindowResize()
1505
906
  {
1506
- return this._averageLoad;
907
+ this._getChartWidget('ccu').redraw();
908
+ this._getChartWidget('cpu').redraw();
909
+ this._getChartWidget('mem').redraw();
910
+ this._getChartWidget('thd').redraw();
911
+ this._getChartWidget('net').redraw();
1507
912
  }
1508
- }
1509
-
1510
- // DEFINE COMPONENT
1511
- if (!window.customElements.get('system-queue-chart'))
1512
- window.customElements.define('system-queue-chart', SystemQueueChart);
1513
-
1514
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1515
-
1516
- /***/ }),
1517
913
 
1518
- /***/ "./src/components/charts/system-workload-chart.js":
1519
- /*!********************************************************!*\
1520
- !*** ./src/components/charts/system-workload-chart.js ***!
1521
- \********************************************************/
1522
- /*! exports provided: SystemWorkloadChart */
1523
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1524
-
1525
- "use strict";
1526
- __webpack_require__.r(__webpack_exports__);
1527
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SystemWorkloadChart", function() { return SystemWorkloadChart; });
1528
- /* harmony import */ var _base_chart__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-chart */ "./src/components/charts/base-chart.js");
1529
- /* harmony import */ var _chart_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chart-utils */ "./src/components/charts/chart-utils.js");
1530
-
1531
-
1532
-
1533
-
1534
- class SystemWorkloadChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseChart"]
1535
- {
1536
- constructor()
914
+ destroy()
1537
915
  {
1538
- super(240);
916
+ $(window).off('resize');
1539
917
  }
1540
918
 
1541
- _initialize()
919
+ addChartEntries(type, data, data1, intervalMillis)
1542
920
  {
1543
- const chartHeight = 240;
1544
-
1545
- // Append container for chart & gauge
1546
- let container = $('<div>', {class: 'd-flex flex-row'});
1547
- $(this).append(container);
1548
-
1549
- // CHART
1550
-
1551
- let chartContainer = $('<div>', {class: 'flex-grow-1'});
1552
- container.append(chartContainer);
1553
-
1554
- // Create chart html
1555
- let chartHtml = $('<div>');
1556
- chartContainer.append(chartHtml);
1557
-
1558
- // Initialize chart
1559
- this._chartWidget = this._initChartWidget(chartHtml, chartHeight);
1560
-
1561
- // Append text to display elapsed time
1562
- this._elapsedTxt = $('<div>', {class: 'text-center', text: '---'});
1563
- chartContainer.append(this._elapsedTxt);
1564
-
1565
- // GAUGE
1566
-
1567
- let gaugeContainer = $('<div>');
1568
- container.append(gaugeContainer);
1569
-
1570
- // Create gauge html
1571
- let gaugeHtml = $('<div>');
1572
- gaugeContainer.append(gaugeHtml);
1573
-
1574
- // Initialize gauge
1575
- this._gaugeWidget = this._initGaugeWidget(gaugeHtml, chartHeight);
921
+ let lastTimestamp = data.getLong('last');
922
+ let values = data.getLongArray('data');
923
+ let values1 = (data1 != null ? data1.getLongArray('data') : null);
924
+ let chartWidget = this._getChartWidget(type);
1576
925
 
1577
- // Append text to display load
1578
- this._loadTxt = $('<div>', {class: 'text-center font-weight-bold', text: '---'});
1579
- gaugeContainer.append(this._loadTxt);
1580
-
1581
- //------------------------------
1582
-
1583
- // Reset data source
1584
- this.reset();
926
+ this._addChartEntries(chartWidget, values, values1, intervalMillis, lastTimestamp);
1585
927
  }
1586
928
 
1587
- _initChartWidget(chartHtml, height)
929
+ _addChartEntries(chartWidget, values, values1, intervalMillis, lastTimestamp)
1588
930
  {
1589
- return chartHtml.kendoChart({
1590
- transitions: false,
1591
- chartArea: {
1592
- height: height,
1593
- background: 'transparent'
1594
- },
1595
- legend: {
1596
- visible: false
1597
- },
1598
- seriesDefaults: {
1599
- type: 'area',
1600
- labels: {
1601
- visible: false,
1602
- format: '{0}%',
1603
- background: 'transparent'
1604
- }
1605
- },
1606
- series: [
1607
- {
1608
- name: 'Workload',
1609
- field: 'load',
1610
- categoryField: 'time',
1611
- color: '#3399ff',
1612
- line: {
1613
- width: 2
1614
- }
1615
- }
1616
- ],
1617
- valueAxis: {
1618
- labels: {
1619
- format: '{0}%'
1620
- },
1621
- line: {
1622
- visible: false
1623
- },
1624
- min: 0,
1625
- max: 100
1626
- },
1627
- categoryAxis: {
1628
- majorGridLines: {
1629
- visible: false
1630
- },
1631
- majorTicks: {
1632
- visible: false
1633
- },
1634
- labels: {
1635
- visible: false
1636
- }
1637
- },
1638
- tooltip: {
1639
- shared: true,
1640
- visible: true,
1641
- sharedTemplate: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getBasicSharedTemplate"])('{0}%'),
1642
- background: '#e4e4e4'
1643
- }
1644
- }).data('kendoChart');
1645
- }
931
+ // Divide interval by the number of data points to calculate their timestamps
932
+ let sliceMillis = Math.round(intervalMillis / values.length);
1646
933
 
1647
- _initGaugeWidget(gaugeHtml, height)
1648
- {
1649
- return gaugeHtml.kendoLinearGauge({
1650
- pointer: {
1651
- value: 0,
1652
- shape: 'arrow',
1653
- size: 10,
1654
- color: '#212529'
1655
- },
1656
- gaugeArea: {
1657
- height: height
1658
- },
1659
- scale: {
1660
- majorUnit: 10,
1661
- minorUnit: 1,
1662
- max: 100,
1663
- min: 0,
1664
- ranges: [
1665
- {
1666
- from: 0,
1667
- to: 50,
1668
- color: '#00cc00',
1669
- opacity: .5
1670
- }, {
1671
- from: 50,
1672
- to: 75,
1673
- color: '#ffe106',
1674
- opacity: .5
1675
- }, {
1676
- from: 75,
1677
- to: 100,
1678
- color: '#ed1601',
1679
- opacity: .5
1680
- }
1681
- ],
1682
- majorTicks: {
1683
- visible: true,
1684
- size: 10
1685
- },
1686
- minorTicks: {
1687
- visible: false
1688
- },
1689
- labels: {
1690
- visible: false
1691
- },
1692
- line: {
1693
- visible: false
1694
- },
1695
- rangeSize: 10
1696
- }
1697
- }).data('kendoLinearGauge');
1698
- }
1699
-
1700
- addEntry(load)
1701
- {
1702
- // CHART
1703
-
1704
- let now = new Date();
1705
-
1706
- let newEntry = {
1707
- time: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getFormattedDateTime"])(now),
1708
- timestamp: now.getTime(),
1709
- load: load
1710
- };
1711
-
1712
- // Add entry to chart
1713
- super._addEntry(newEntry);
934
+ let ds = new kendo.data.DataSource();
935
+ let firstTimestamp = lastTimestamp - intervalMillis;
1714
936
 
1715
- // Update x axis
1716
- if (!this.isPaused)
1717
- this._updateElapsedText();
1718
-
1719
- // GAUGE
937
+ for (let i = 0; i < values.length; i++)
938
+ {
939
+ let timestamp = firstTimestamp + (sliceMillis * i);
1720
940
 
1721
- // Evaluate average
1722
- let numValues = this._dataSource.total();
1723
- let averageLoad = 0;
941
+ let value = values[i] < 0 ? null : values[i];
942
+ let value1 = values1 ? (values1[i] < 0 ? null : values1[i]) : null;
1724
943
 
1725
- if (numValues > 0)
1726
- {
1727
- let total = 0;
1728
- for (let i = 0; i < numValues; i++)
1729
- total += this._dataSource.at(i).load;
944
+ let entry = {
945
+ ts: timestamp,
946
+ val: value,
947
+ val1: value1,
948
+ };
1730
949
 
1731
- averageLoad = Math.round(total / numValues);
950
+ ds.add(entry);
1732
951
  }
1733
952
 
1734
- // Set gauge value
1735
- this._gaugeWidget.value(averageLoad);
953
+ // Set chart's x-axis limits
954
+ chartWidget.options.xAxis.min = firstTimestamp;
955
+ chartWidget.options.xAxis.max = lastTimestamp;
1736
956
 
1737
- // Set load text
1738
- this._loadTxt.text(averageLoad + '%')
957
+ chartWidget.setDataSource(ds);
1739
958
  }
1740
959
 
1741
- _updateElapsedText()
960
+ _getChartDiv(type)
1742
961
  {
1743
- let ds = this._dataSource;
1744
-
1745
- if (ds.total() > 1)
1746
- {
1747
- // Get axis limits
1748
- const chartMinimum = ds.at(0).timestamp;
1749
- const chartMaximum = ds.at(ds.total() - 1).timestamp;
1750
-
1751
- // Set elapsed text
1752
- let seconds = Math.round( (chartMaximum - chartMinimum) / 1000 );
1753
- let title;
1754
-
1755
- if (seconds < 60)
1756
- title = 'Last ' + (seconds != 1 ? seconds + ' seconds' : 'second');
1757
- else
1758
- {
1759
- const minutes = Math.floor(seconds / 60);
1760
- title = 'Last ' + (minutes != 1 ? minutes + ' minutes' : 'minute');
1761
- }
1762
-
1763
- this._elapsedTxt.text(title);
1764
- }
962
+ return $('.chart-container[data-type="' + type + '"] .chart', this.shadowRoot);
1765
963
  }
1766
964
 
1767
- get load()
965
+ _getChartWidget(type)
1768
966
  {
1769
- return this._averageLoad;
967
+ return this._getChartDiv(type).data('kendoChart');
1770
968
  }
1771
- }
1772
-
1773
- // DEFINE COMPONENT
1774
- if (!window.customElements.get('system-workload-chart'))
1775
- window.customElements.define('system-workload-chart', SystemWorkloadChart);
1776
969
 
1777
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1778
-
1779
- /***/ }),
1780
-
1781
- /***/ "./src/components/charts/thread-count-chart.js":
1782
- /*!*****************************************************!*\
1783
- !*** ./src/components/charts/thread-count-chart.js ***!
1784
- \*****************************************************/
1785
- /*! exports provided: ThreadCountChart */
1786
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
1787
-
1788
- "use strict";
1789
- __webpack_require__.r(__webpack_exports__);
1790
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ThreadCountChart", function() { return ThreadCountChart; });
1791
- /* harmony import */ var _base_chart__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-chart */ "./src/components/charts/base-chart.js");
1792
- /* harmony import */ var _chart_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./chart-utils */ "./src/components/charts/chart-utils.js");
1793
-
1794
-
1795
-
1796
-
1797
- class ThreadCountChart extends _base_chart__WEBPACK_IMPORTED_MODULE_0__["BaseChart"]
1798
- {
1799
- constructor()
970
+ _onChartContainerClick(e)
1800
971
  {
1801
- super(120);
1802
- }
972
+ let chartType = $(e.currentTarget).data('type');
1803
973
 
1804
- _initChartWidget(chartHtml)
1805
- {
1806
- return chartHtml.kendoChart({
1807
- transitions: false,
1808
- chartArea: {
1809
- height: 120,
1810
- background: 'transparent'
974
+ // Dispatch custom event
975
+ let evt = new CustomEvent('chartClick', {
976
+ detail: {
977
+ type: chartType,
978
+ node: this.nId,
979
+ options: this._getChartWidget(chartType).options
1811
980
  },
1812
- legend: {
1813
- visible: false
1814
- },
1815
- seriesDefaults: {
1816
- type: 'area',
1817
- labels: {
1818
- visible: false,
1819
- format: '{0}',
1820
- background: 'transparent'
1821
- },
1822
- },
1823
- series: [
1824
- {
1825
- name: 'Threads',
1826
- field: 'threads',
1827
- categoryField: 'time',
1828
- color: this.threadsColor,
1829
- line: {
1830
- width: 2
1831
- }
1832
- }
1833
- ],
1834
- valueAxis: {
1835
- min: 0,
1836
- labels: {
1837
- format: '{0}'
1838
- },
1839
- line: {
1840
- visible: false
1841
- },
1842
- },
1843
- categoryAxis: {
1844
- majorGridLines: {
1845
- visible: false
1846
- },
1847
- majorTicks: {
1848
- visible: false
1849
- },
1850
- labels: {
1851
- visible: false
1852
- }
1853
- },
1854
- tooltip: {
1855
- shared: true,
1856
- visible: true,
1857
- sharedTemplate: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getBasicSharedTemplate"])(),
1858
- background: '#e4e4e4'
1859
- }
1860
- }).data('kendoChart');
1861
- }
1862
-
1863
- get threadsColor()
1864
- {
1865
- return '#3399FF';
1866
- }
1867
-
1868
- addEntry(threads)
1869
- {
1870
- let newEntry = {
1871
- time: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_1__["getFormattedDateTime"])(new Date()),
1872
- threads: threads
1873
- };
981
+ bubbles: true,
982
+ cancelable: false,
983
+ composed: true // Allows event to bubble outside of Custom Element
984
+ });
1874
985
 
1875
- // Add entry to chart
1876
- super._addEntry(newEntry);
986
+ this.dispatchEvent(evt);
1877
987
  }
1878
988
  }
1879
989
 
1880
990
  // DEFINE COMPONENT
1881
- if (!window.customElements.get('thread-count-chart'))
1882
- window.customElements.define('thread-count-chart', ThreadCountChart);
991
+ if (!window.customElements.get('node-mini-charts'))
992
+ window.customElements.define('node-mini-charts', NodeMiniCharts);
1883
993
 
994
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1884
995
 
1885
996
  /***/ }),
1886
997
 
1887
- /***/ "./src/modules/dashboard.js":
1888
- /*!**********************************!*\
1889
- !*** ./src/modules/dashboard.js ***!
1890
- \**********************************/
998
+ /***/ "./src/modules/cluster-monitor.js":
999
+ /*!****************************************!*\
1000
+ !*** ./src/modules/cluster-monitor.js ***!
1001
+ \****************************************/
1891
1002
  /*! exports provided: default */
1892
1003
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
1893
1004
 
1894
1005
  "use strict";
1895
1006
  __webpack_require__.r(__webpack_exports__);
1896
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return Dashboard; });
1007
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ClusterMonitor; });
1897
1008
  /* harmony import */ var _base_module__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-module */ "./src/modules/base-module.js");
1898
- /* harmony import */ var _utils_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/utilities */ "./src/utils/utilities.js");
1899
- /* harmony import */ var _components_charts_chart_utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../components/charts/chart-utils */ "./src/components/charts/chart-utils.js");
1900
- /* harmony import */ var _components_charts_cpu_usage_chart__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../components/charts/cpu-usage-chart */ "./src/components/charts/cpu-usage-chart.js");
1901
- /* harmony import */ var _components_charts_thread_count_chart__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../components/charts/thread-count-chart */ "./src/components/charts/thread-count-chart.js");
1902
- /* harmony import */ var _components_charts_memory_chart__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../components/charts/memory-chart */ "./src/components/charts/memory-chart.js");
1903
- /* harmony import */ var _components_charts_network_realtime_chart__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../components/charts/network-realtime-chart */ "./src/components/charts/network-realtime-chart.js");
1904
- /* harmony import */ var _components_charts_network_24h_chart__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../components/charts/network-24h-chart */ "./src/components/charts/network-24h-chart.js");
1905
- /* harmony import */ var _components_charts_system_workload_chart__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../components/charts/system-workload-chart */ "./src/components/charts/system-workload-chart.js");
1906
- /* harmony import */ var _components_charts_system_queue_chart__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../components/charts/system-queue-chart */ "./src/components/charts/system-queue-chart.js");
1907
-
1908
-
1909
-
1910
-
1911
-
1912
-
1009
+ /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! moment */ "./node_modules/moment/moment.js");
1010
+ /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_1__);
1011
+ /* harmony import */ var _utils_utilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils/utilities */ "./src/utils/utilities.js");
1012
+ /* harmony import */ var _components_module_specific_cluster_monitor_node_mini_charts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../components/module-specific/cluster-monitor/node-mini-charts */ "./src/components/module-specific/cluster-monitor/node-mini-charts.js");
1913
1013
 
1914
1014
 
1915
1015
 
1916
1016
 
1917
1017
 
1918
- class Dashboard extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
1018
+ class ClusterMonitor extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
1919
1019
  {
1920
1020
  constructor()
1921
1021
  {
1922
- super('dashboard');
1022
+ super('clusterMon');
1023
+
1024
+ this.MAX_LOG_SIZE = 100;
1923
1025
 
1924
1026
  // Outgoing requests
1925
- this.REQ_INIT = 'init';
1926
- this.REQ_GET_DATA = 'getData';
1927
- this.REQ_DUMP_THREADS = 'getThDump';
1027
+ this.REQ_GET_NODES = 'getNodes';
1028
+ this.REQ_DEACTIVATE_NODES = 'deact';
1029
+ this.REQ_GET_NODES_DATA = 'getDataN';
1030
+ this.REQ_GET_CHART_DATA = 'getDataC';
1031
+ this.REQ_SCALE_UP = 'scaleUp';
1032
+ this.REQ_GET_LOG_MESSAGES = 'getLog';
1033
+
1034
+ // Incoming responses
1035
+ this.RESP_NODES = 'nodes';
1036
+ this.RESP_NODES_DATA = 'dataN';
1037
+ this.RESP_CHART_DATA = 'dataC';
1038
+ this.RESP_LOG_MESSAGES = 'log';
1039
+
1040
+ this.intervals = [
1041
+ {
1042
+ label: 'Last hour',
1043
+ minutes: 60,
1044
+ points1: 30,
1045
+ points2: 30,
1046
+ },
1047
+ {
1048
+ label: 'Last 3 hours',
1049
+ minutes: 180,
1050
+ points1: 30,
1051
+ points2: 90,
1052
+ },
1053
+ {
1054
+ label: 'Last 12 hours',
1055
+ minutes: 720,
1056
+ points1: 30,
1057
+ points2: 180,
1058
+ },
1059
+ {
1060
+ label: 'Last 24 hours',
1061
+ minutes: 1440,
1062
+ points1: 30,
1063
+ points2: 360,
1064
+ },
1065
+ ]
1928
1066
 
1929
- // Incoming responses
1930
- this.RESP_INIT = 'init';
1931
- this.RESP_DATA = 'data';
1932
- this.RESP_THREAD_DUMP = 'thDump';
1933
-
1934
- this._tcpOutThreads = 0;
1935
- this._tcpOutLoad = 0;
1936
- this._udpOutThreads = 0;
1937
- this._udpOutLoad = 0;
1067
+ this._selectedNodes = [];
1068
+ this._selectedActiveNodes = [];
1069
+ this._chartedNodes = [];
1070
+ this._chartInfo = null;
1071
+ this._lastLogsReqTimestamp = 0;
1938
1072
  }
1939
1073
 
1940
1074
  //------------------------------------
@@ -1949,7 +1083,7 @@ class Dashboard extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
1949
1083
  super.initialize(idData, shellController);
1950
1084
 
1951
1085
  // Initialize scrolling tabs
1952
- $('#dsh-tabNavigator > #tabs').scrollingTabs({
1086
+ $('#clm-tabNavigator > #tabs').scrollingTabs({
1953
1087
  bootstrapVersion: 4,
1954
1088
  scrollToTabEdge: true,
1955
1089
  enableSwiping: true,
@@ -1958,135 +1092,266 @@ class Dashboard extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
1958
1092
  cssClassRightArrow: 'fa fa-chevron-right'
1959
1093
  });
1960
1094
 
1961
- // Initialize interval dropdown
1962
- this._intervalDropDown = $('#dsh-intervalDD').kendoDropDownList({
1963
- valueTemplate: '<span class="text-muted pr-1">Interval:</span><span>#:data.text#</span>',
1964
- change: $.proxy(this._onUpdateIntervalChange, this)
1965
- }).data('kendoDropDownList');
1095
+ // Initialize buttons
1096
+ $('#clm-deactivateBt').on('click', $.proxy(this._onDeactivateBtClick, this));
1097
+ $('#clm-scaleUpBt').on('click', $.proxy(this._onScaleUpBtClick, this));
1098
+ $('#clm-scaleUpModalBt').on('click', $.proxy(this._onScaleUpConfirmBtClick, this));
1099
+ $('#clm-refreshBt').on('click', $.proxy(this._requestNodesList, this));
1966
1100
 
1967
- // Initialize threads grid
1968
- this._threadsGrid = $('#dsh-threadsGrid').kendoGrid({
1969
- dataSource: this._getThreadsGridDataSource(),
1101
+ // Initialize grid
1102
+ this._grid = $('#clm-nodesList').kendoGrid({
1970
1103
  scrollable: true,
1971
1104
  sortable: true,
1972
- filterable: false,
1973
- resizable: true,
1105
+ //resizable: true,
1974
1106
  selectable: false,
1975
- columns: [
1107
+ columns: [
1976
1108
  {
1977
- field: 'id',
1978
- title: 'Id',
1979
- width: 60
1109
+ selectable: true,
1110
+ width: 41
1980
1111
  },
1981
1112
  {
1982
- field: 'name',
1983
- title: 'Name',
1984
- width: '65%'
1985
- },
1113
+ field: 'name',
1114
+ width: 250,
1115
+ title: 'Node',
1116
+ template: function(dataItem) {
1117
+ if (dataItem['alias'])
1118
+ return '<div class="name-cell"><span>' + dataItem['alias'] + '</span> <a href="http://' + dataItem['name'] + ':8080/admin" class="name-admin-link" target="_blank"><i class="fas fa-toolbox"></i></a><br><small class="text-muted">' + dataItem['name'] + '<small></div>';
1119
+ else
1120
+ return '<div class="name-cell"><span>' + dataItem['name'] + '</span> <a href="http://' + dataItem['name'] + ':8080/admin" class="name-admin-link" target="_blank"><i class="fas fa-toolbox"></i></a></div>';
1121
+ }
1122
+ },
1123
+ {
1124
+ field: 'ccu',
1125
+ width: 80,
1126
+ title: 'CCU',
1127
+ },
1128
+ {
1129
+ field: 'cpu',
1130
+ width: 80,
1131
+ title: 'CPU',
1132
+ template: function(dataItem) {
1133
+ return Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_2__["roundToDecimals"])(dataItem['cpu'], 2) + '%';
1134
+ }
1135
+ },
1986
1136
  {
1987
- field: 'cpuTime',
1988
- title: 'CPU Time',
1989
- format: '{0}%',
1990
- width: '35%'
1991
- },
1137
+ title: 'Memory',
1138
+ columns: [
1139
+ {
1140
+ field: 'usedMem',
1141
+ width: 100,
1142
+ title: 'Used',
1143
+ template: function(dataItem) {
1144
+ return Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_2__["bytesToSize"])(dataItem['usedMem']);
1145
+ }
1146
+ },
1147
+ {
1148
+ field: 'allocMem',
1149
+ width: 100,
1150
+ title: 'Allocated',
1151
+ template: function(dataItem) {
1152
+ return Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_2__["bytesToSize"])(dataItem['allocMem']);
1153
+ }
1154
+ }
1155
+ ]
1156
+ },
1157
+ {
1158
+ title: 'Network',
1159
+ columns: [
1160
+ {
1161
+ field: 'netIn',
1162
+ width: 100,
1163
+ title: 'In',
1164
+ template: function(dataItem) {
1165
+ return (dataItem['netIn'] > -1 ? Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_2__["bytesToSize"])(dataItem['netIn'], 2, 'KB', '/s') : '&ndash;');
1166
+ }
1167
+ },
1168
+ {
1169
+ field: 'netOut',
1170
+ width: 100,
1171
+ title: 'Out',
1172
+ template: function(dataItem) {
1173
+ return (dataItem['netOut'] > -1 ? Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_2__["bytesToSize"])(dataItem['netOut'], 2, 'KB', '/s') : '&ndash;');
1174
+ }
1175
+ }
1176
+ ]
1177
+ },
1178
+ {
1179
+ field: 'threads',
1180
+ width: 100,
1181
+ title: 'Threads',
1182
+ },
1183
+ {
1184
+ field: 'rooms',
1185
+ width: 100,
1186
+ title: 'Rooms',
1187
+ },
1188
+ {
1189
+ field: 'joinTime',
1190
+ width: 100,
1191
+ title: 'Joined',
1192
+ sortable: false,
1193
+ template: $.proxy(this._getTimeSinceJoinTemplate, this)
1194
+ },
1195
+ {
1196
+ field: 'health',
1197
+ width: 75,
1198
+ title: 'Health',
1199
+ sortable: false,
1200
+ template: $.proxy(this._getHealthTemplate, this)
1201
+ },
1202
+ {
1203
+ field: 'recyclable',
1204
+ width: 45,
1205
+ title: 'R.',
1206
+ sortable: false,
1207
+ template: $.proxy(this._getRecyclableTemplate, this)
1208
+ },
1209
+ {
1210
+ field: 'terminable',
1211
+ width: 45,
1212
+ title: 'T.',
1213
+ sortable: false,
1214
+ template: $.proxy(this._getTerminableTemplate, this)
1215
+ },
1992
1216
  ],
1993
1217
  noRecords: {
1994
- template: 'No threads.'
1218
+ template: 'No game nodes.'
1995
1219
  },
1996
- height: 'calc(240px - .75rem + 1rem)'
1997
- }).data('kendoGrid');
1220
+ dataSource: {
1221
+ schema: {
1222
+ model: {
1223
+ id: 'id',
1224
+ // fields: {
1225
+ // id: { type: 'string' },
1226
+ // active: { type: 'boolean' }
1227
+ // }
1228
+ }
1229
+ },
1230
+ group: {
1231
+ field: 'active',
1232
+ dir: 'desc',
1233
+ }
1234
+ },
1235
+ change: $.proxy(this._onNodesGridChange, this),
1236
+ dataBound: $.proxy(this._onNodesGridDataBound, this),
1237
+ }).data('kendoGrid');
1998
1238
 
1999
- // Add click listener to threads dump button
2000
- $('#dsh-dumpThreadsBt').on('click', $.proxy(this._onDumpThreadsClick, this));
1239
+ // Add listener to mini charts container
1240
+ $('#clm-nodeMiniChartsContainer').on('chartClick', $.proxy(this._onMiniChartClick, this));
2001
1241
 
2002
- // Configure thread dump panel
2003
- $('#dsh-threadDumpModal').modal({
1242
+ // Configure detail chart modal
1243
+ $('#clm-chartModal').modal({
2004
1244
  backdrop: 'static',
2005
1245
  keyboard: false,
2006
1246
  show: false,
2007
1247
  });
2008
1248
 
2009
- // Add listener for threads dump panel hide
2010
- $('#dsh-threadDumpModal').on('hidden.bs.modal', $.proxy(this._onThreadDumpModalHidden, this));
1249
+ // Add event listener for modal hidden event
1250
+ $('#clm-chartModal').on('hidden.bs.modal', $.proxy(this._onChartModalHidden, this));
1251
+
1252
+ // Initialize data interval dropdowns
1253
+ let items = [];
1254
+ for (let i = 0; i < this.intervals.length; i++)
1255
+ items.push({label:this.intervals[i].label, value:i});
1256
+
1257
+ this._mainRangeDD = $('#clm-mainRangeDD').kendoDropDownList({
1258
+ dataTextField: 'label',
1259
+ dataValueField: 'value',
1260
+ dataSource: items,
1261
+ index: 0,
1262
+ //valueTemplate: '<span class="text-muted pr-1">Last </span><span>#:data.text#</span>',
1263
+ change: $.proxy(this._onMainRangeChange, this)
1264
+ }).data('kendoDropDownList');
2011
1265
 
2012
- // Add click listener to threads dump copy button
2013
- $('#dsh-copyThreadDumpBt').on('click', $.proxy(this._onCopyThreadDumpClick, this));
1266
+ $('#clm-mainRangeContainer').hide();
2014
1267
 
2015
- // Initialize time range slider
2016
- this._timeSlider = $('#dsh-timeSlider').kendoRangeSlider({
2017
- min: -24,
2018
- max: 0,
2019
- smallStep: 1,
2020
- largeStep: 0,
2021
- change: $.proxy(this._onTimeRangeChange, this),
2022
- tooltip: {
2023
- template: Object(_components_charts_chart_utils__WEBPACK_IMPORTED_MODULE_2__["getTimeRangeTooltipTemplate"])()
1268
+ this._chartRangeDD = $('#clm-chartRangeDD').kendoDropDownList({
1269
+ dataTextField: 'label',
1270
+ dataValueField: 'value',
1271
+ dataSource: items,
1272
+ index: 0,
1273
+ //valueTemplate: '<span class="text-muted pr-1">Last </span><span>#:data.text#</span>',
1274
+ change: $.proxy(this._onChartRangeChange, this)
1275
+ }).data('kendoDropDownList');
1276
+
1277
+ // Initialize lobby state info
1278
+ $('#clm-lobbyState').hide();
1279
+
1280
+ // Configure scale-up modal
1281
+ $('#clm-scaleUpModal').modal({
1282
+ backdrop: 'static',
1283
+ keyboard: false,
1284
+ show: false,
1285
+ });
1286
+
1287
+ // Init nodes' number numeric stepper in scale-up modal
1288
+ this._numNodesIn = $('#clm-numNodesNS').kendoNumericTextBox({
1289
+ min: 1,
1290
+ max: 5,
1291
+ step: 1,
1292
+ format: '#'
1293
+ }).data('kendoNumericTextBox');
1294
+
1295
+ // Initialize kendo validation on scale-up form
1296
+ this._scaleUpValidator = $('#clm-scaleUpForm').kendoValidator({}).data('kendoValidator');
1297
+
1298
+ // Add listener for scale-up panel hide
1299
+ $('#clm-scaleUpModal').on('hidden.bs.modal', $.proxy(this._onScaleUpModalHidden, this));
1300
+
1301
+ // Initialize orchestration log grid
1302
+ this._logGrid = $('#clm-logGrid').kendoGrid({
1303
+ dataSource: [],
1304
+ resizable: true,
1305
+ selectable: false,
1306
+ noRecords: {
1307
+ template: 'No entries.'
2024
1308
  },
2025
- leftDragHandleTitle: 'Drag',
2026
- rightDragHandleTitle: 'Drag',
2027
- }).data('kendoRangeSlider');
2028
-
2029
- // Add click listener to reset charts button
2030
- $('#dsh-resetBt').on('click', $.proxy(this._onResetChartsClick, this));
2031
-
2032
- // Add click listener to play & pause chart update buttons
2033
- $('#dsh-pauseBt').on('click', $.proxy(this._onPauseUpdateClick, this));
2034
- $('#dsh-playBt').on('click', $.proxy(this._onPlayUpdateClick, this));
2035
-
2036
- // Set reference to charts
2037
- this._cpuUsageChart = document.getElementById('dsh-cpuUsageChart');
2038
- this._threadCountChart = document.getElementById('dsh-threadCountChart');
2039
- this._memoryChart = document.getElementById('dsh-memoryChart');
2040
- this._networkRTChart = document.getElementById('dsh-networkRTChart');
2041
- this._network24hChart = document.getElementById('dsh-network24hChart');
2042
- this._sysWorkloadChart = document.getElementById('dsh-systemWorkloadChart');
2043
- this._outTcpMsgQueueChart = document.getElementById('dsh-outgoingTcpMessagesQueueChart');
2044
- this._outUdpMsgQueueChart = document.getElementById('dsh-outgoingUdpMessagesQueueChart');
2045
- this._sysQueueChart = document.getElementById('dsh-systemQueueChart');
2046
- this._extQueueChart = document.getElementById('dsh-extensionQueueChart');
2047
-
2048
- // Set colors in chart legends
2049
- $('#dsh-systemLoadColor').css('color', this._cpuUsageChart.systemColor);
2050
- $('#dsh-processLoadColor').css('color', this._cpuUsageChart.processColor);
2051
- $('#dsh-allocMemColor').css('color', this._memoryChart.allocatedColor);
2052
- $('#dsh-usedMemColor').css('color', this._memoryChart.usedColor);
2053
- $('#dsh-incomingNetColor').css('color', this._networkRTChart.incomingColor);
2054
- $('#dsh-outgoingNetColor').css('color', this._networkRTChart.outgoingColor);
2055
-
2056
- // Reset time range on 24h network chart
2057
- this._onTimeRangeChange();
2058
-
2059
- // Add listener to redraw all charts on main tab change
2060
- // (to work around an issue with the chart resizing to default width when pane is hidden)
2061
- $('a[data-toggle="tab"]').on('shown.bs.tab', $.proxy(this._onWindowResize, this));
2062
-
2063
- // Add listener to redraw network charts on network tab change
2064
- // (to work around an issue with the chart resizing to default width when pane is hidden)
2065
- $('#dsh-networkPills a[data-toggle="pill"]').on('shown.bs.tab', $.proxy(this._redrawNetworkCharts, this));
2066
-
2067
- // Add listener to redraw outgoing messages queue charts on tab change
2068
- // (to work around an issue with the chart resizing to default width when pane is hidden)
2069
- $('#dsh-msgQueuePills a[data-toggle="pill"]').on('shown.bs.tab', $.proxy(this._redrawOutMsgCharts, this));
2070
-
2071
- // Add listener to redraw all charts in case of window resize
2072
- $(window).on('resize', $.proxy(this._onWindowResize, this));
2073
- this._onWindowResize(); // Also do it immediately
1309
+ columns: [
1310
+ {
1311
+ field: 'timestamp',
1312
+ title: 'Timestamp',
1313
+ width: 180
1314
+ },
1315
+ {
1316
+ field: 'level',
1317
+ title: 'Level',
1318
+ width: 100
1319
+ },
1320
+ {
1321
+ field: 'message',
1322
+ title: 'Message',
1323
+ width: 400
1324
+ },
1325
+ ],
1326
+ dataBound: function() {
1327
+ this.content.scrollTop(this.tbody.height()); // Scroll to bottom
1328
+ }
1329
+ }).data('kendoGrid');
1330
+
1331
+ $('#clm_maxLogMsgs').text(this.MAX_LOG_SIZE);
2074
1332
 
2075
- // Add listener to show help tooltips in queues status tab
2076
- $('#dsh-queues').kendoTooltip({
1333
+ // Initialize help tooltips
1334
+ $(this).kendoTooltip({
2077
1335
  filter: 'i[title].help',
2078
1336
  position: 'right',
2079
- width: '250px',
2080
1337
  content: function(e) {
2081
1338
  return `<div class="help-tooltip">${e.target.data('title')}</div>`;
2082
1339
  }
2083
1340
  });
2084
1341
 
2085
- // Add listener to regenerate link to open web server external manager console
2086
- $('#dsh-useHttpsCheck').on('change', $.proxy(this._onUseHttpsForWsManagerChange, this));
1342
+ //-------------------------------------------------------
2087
1343
 
2088
- // Send initialization request
2089
- this.sendExtensionRequest(this.REQ_INIT);
1344
+ // Request nodes list to server
1345
+ this._requestNodesList();
1346
+
1347
+ // Schedule continuous data request for the selected nodes
1348
+ this._requestDataTimer = setInterval($.proxy(this._onRequestDataInterval, this), 60000); // 1 minute
1349
+
1350
+ // Request orchestration logs to server
1351
+ this._requestOrchestrationLogs();
1352
+
1353
+ // Schedule continuous orchestration logs request
1354
+ this._requestLogsTimer = setInterval($.proxy(this._requestOrchestrationLogs, this), 3000); // 3 seconds
2090
1355
  }
2091
1356
 
2092
1357
  destroy()
@@ -2095,224 +1360,207 @@ class Dashboard extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
2095
1360
  super.destroy();
2096
1361
 
2097
1362
  // Destroy scrolling tabs
2098
- $('#dsh-tabNavigator #tabs').scrollingTabs('destroy');
2099
-
2100
- // Remove other listeners
2101
- $('#dsh-resetBt').off('click');
2102
- $('#dsh-pauseBt').off('click');
2103
- $('#dsh-playBt').off('click');
2104
- $('#dsh-dumpThreadsBt').off('click');
2105
- $('a[data-toggle="tab"]').off('shown.bs.tab');
2106
- $('a[data-toggle="pill"]').off('shown.bs.tab');
2107
- $(window).off('resize');
2108
- $('#dsh-useHttpsCheck').off('change');
1363
+ $('#clm-tabNavigator #tabs').scrollingTabs('destroy');
2109
1364
 
2110
- // Remove thread dump panel listener
2111
- $('#dsh-threadDumpModal').off('hidden.bs.modal');
1365
+ // Hide modals
1366
+ $('#clm-chartModal').modal('hide');
1367
+ $('#clm-scaleUpModal').modal('hide');
2112
1368
 
2113
- // Clear request scheduling
2114
- clearTimeout(this._requestTimer);
1369
+ // Remove click listeners
1370
+ $('#clm-refreshBt').off('click');
1371
+ $('#clm-scaleUpBt').off('click');
1372
+ $('#clm-scaleUpModalBt').off('click');
1373
+ $('#clm-nodeMiniChartsContainer').off('chartClick');
1374
+
1375
+ // Remove scale-up panel listener
1376
+ $('#clm-scaleUpModal').off('hidden.bs.modal');
1377
+
1378
+ // Clear nodes, data and logs request scheduling
1379
+ clearTimeout(this._requestNodesTimer);
1380
+ clearInterval(this._requestDataTimer);
1381
+ clearInterval(this._requestLogsTimer);
2115
1382
  }
2116
1383
 
2117
1384
  onExtensionCommand(command, data)
2118
1385
  {
2119
- // Initialization data received
2120
- if (command == this.RESP_INIT)
2121
- {
2122
- // Server sends flags indicating if web server's internal manager is accessible and how
2123
- this._wsManagerConfig = {
2124
- hasAccess: data.getBool('hasWsManager'),
2125
- httpEnabled: data.getBool('httpEnabled'),
2126
- httpsEnabled: data.getBool('httpsEnabled'),
2127
- httpPort: data.getInt('httpPort'),
2128
- httpsPort: data.getInt('httpsPort'),
2129
- }
2130
-
2131
- // Enable access to web server manager console
2132
- this._enableWebServerManagerAccess();
2133
-
2134
- // Request data to server
2135
- this._requestData(true);
2136
- }
2137
-
2138
- // Data received
2139
- else if (command == this.RESP_DATA)
1386
+ if (command == this.RESP_NODES)
2140
1387
  {
2141
- // CPU LOAD CHART
1388
+ let nodesObj = data.getSFSArray('nodes');
2142
1389
 
2143
- this._cpuUsageChart.addEntry(data.getDouble('pCpu'), data.getDouble('sCpu'));
2144
- $('#dsh-systemLoadLabel').text(data.getDouble('sCpu'));
2145
- $('#dsh-processLoadLabel').text(data.getDouble('pCpu'));
1390
+ let nodes = [];
1391
+ let nodesIds = [];
2146
1392
 
2147
- // As system cpu load is not always available (for example on MacOS X), let's hide it in case it isn't
2148
- if (data.getDouble('sCpu') < 0)
2149
- $('#dsh-systemLoadLegend').hide();
1393
+ for (let i = 0; i < nodesObj.size(); i++)
1394
+ {
1395
+ let node = nodesObj.getSFSArray(i);
1396
+
1397
+ nodesIds.push(node.getUtfString(0));
1398
+
1399
+ nodes.push({
1400
+ 'id': node.getUtfString(0),
1401
+ 'alias': node.getUtfString(1), // Set in node configuration, but can't be edited - could be removed
1402
+ 'name': node.getUtfString(2), // IP address or domain name
1403
+ 'rooms': node.getInt(3),
1404
+ 'ccu': node.getInt(4),
1405
+ 'threads': node.getInt(5),
1406
+ 'cpu': node.getDouble(6),
1407
+ 'usedMem': node.getLong(7),
1408
+ 'allocMem': node.getLong(8),
1409
+ 'netIn': node.getLong(9),
1410
+ 'netOut': node.getLong(10),
1411
+ 'joinTime': node.getLong(11),
1412
+ 'health': node.getBool(12),
1413
+ 'active': node.getBool(13), // Used for grouping
1414
+ 'recyclable': node.getBool(14),
1415
+ 'terminable': node.getBool(15),
1416
+ });
1417
+ }
2150
1418
 
2151
- // THREADS COUNT CHART
1419
+ // Get nodes grid datasource
1420
+ let ds = this._grid.dataSource;
2152
1421
 
2153
- const threadCount = data.getSFSArray('thList').size();
2154
- this._threadCountChart.addEntry(threadCount);
2155
- $('#dsh-threadsCountLabel').text(threadCount);
1422
+ // --- REMOVE NODES ---
2156
1423
 
2157
- // MEMORY USAGE CHART
2158
- // NOTE: memory data is sent as Bytes by the server
1424
+ let self = this;
1425
+ $.map(ds.data(), function (dataItem, index) {
1426
+ if (dataItem && !nodesIds.includes(dataItem['id']))
1427
+ {
1428
+ // Remove node from datastore
1429
+ ds.remove(dataItem);
2159
1430
 
2160
- const freeMem = data.getLong('freeMem');
2161
- const maxMem = data.getLong('maxMem');
2162
- const totalMem = data.getLong('totalMem');
2163
- const usedMem = totalMem - freeMem;
1431
+ // Remove node from list of selected nodes (if selected)
1432
+ self._selectedNodes = self._selectedNodes.filter(x => x !== dataItem['id']);
1433
+ self._selectedActiveNodes = self._selectedActiveNodes.filter(x => x !== dataItem['id']);
1434
+ }
1435
+ });
2164
1436
 
2165
- this._memoryChart.addEntry(totalMem, usedMem);
2166
- $('#dsh-maxMemoryLabel').text(this._getMemObject(maxMem).label);
2167
- $('#dsh-freeMemoryLabel').text(this._getMemObject(freeMem).label);
1437
+ // Update nodes charts view and nodes deactivate button, in case a selected node was removed
1438
+ this._updateChartedNodes();
1439
+ this._updateDeactivateButton();
2168
1440
 
2169
- // THREADS LIST
1441
+ // --- ADD/UPDATE NODES ---
2170
1442
 
2171
- const totalThreadCpuTime = data.getLong('thCpu');
2172
- let threads = [];
1443
+ let activeNodesCnt = 0;
2173
1444
 
2174
- for (let i = 0; i < data.getSFSArray('thList').size(); i++)
1445
+ for (let node of nodes)
2175
1446
  {
2176
- let threadData = data.getSFSArray('thList').getSFSObject(i);
2177
-
2178
- threads.push({
2179
- id: threadData.getLong('id'),
2180
- name: threadData.getUtfString('name'),
2181
- cpuTime: Math.round(threadData.getLong('cpu') / totalThreadCpuTime * 1000) / 10
2182
- });
2183
- }
1447
+ var dataItem = ds.get(node.id);
2184
1448
 
2185
- // Substitute grid's data source, retaining current sorting
2186
- let currSort = this._threadsGrid.dataSource.sort();
2187
- this._threadsGrid.setDataSource(this._getThreadsGridDataSource(threads, currSort));
2188
-
2189
- // NETWORK TRAFFIC
2190
- // NOTE: network traffic data is sent as KBytes by the server
1449
+ // Update node
1450
+ if (dataItem)
1451
+ {
1452
+ dataItem.set('rooms', node.rooms);
1453
+ dataItem.set('ccu', node.ccu);
1454
+ dataItem.set('threads', node.threads);
1455
+ dataItem.set('cpu', node.cpu);
1456
+ dataItem.set('usedMem', node.usedMem);
1457
+ dataItem.set('allocMem', node.allocMem);
1458
+ dataItem.set('netIn', node.netIn);
1459
+ dataItem.set('netOut', node.netOut);
1460
+ dataItem.set('joinTime', node.joinTime);
1461
+ dataItem.set('health', node.health);
1462
+ dataItem.set('active', node.active);
1463
+ dataItem.set('recyclable', node.recyclable);
1464
+ dataItem.set('terminable', node.terminable);
1465
+
1466
+ dataItem.dirty = false; // Hides "dirty" indicator in grid
1467
+ }
2191
1468
 
2192
- if (data.containsKey('ntOutHistory'))
2193
- {
2194
- const outgoingData = data.getLongArray('ntOutHistory');
2195
- const incomingData = data.getLongArray('ntInHistory');
2196
- const samplingRateMins = data.getInt('ntRate');
2197
- const shiftSeconds = data.getInt('ntShift');
1469
+ // Add node
1470
+ else
1471
+ ds.add(node);
2198
1472
 
2199
- this._network24hChart.addHistoryEntries(outgoingData, incomingData, samplingRateMins * 60, shiftSeconds);
1473
+ // Count active nodes
1474
+ if (node.active)
1475
+ activeNodesCnt++;
2200
1476
  }
2201
1477
 
2202
- // Add current values
2203
- this._network24hChart.addEntry(data.getLong('ntOut'), data.getLong('ntIn'));
2204
- this._networkRTChart.addEntry(data.getLong('ntOut'), data.getLong('ntIn'));
1478
+ // Refresh grid
1479
+ this._grid.refresh();
2205
1480
 
2206
- // TRAFFIC DETAILS
1481
+ // Display global values
1482
+ $('#clm-totalActiveNodes').text(activeNodesCnt);
1483
+ $('#clm-totalInactiveNodes').text(nodes.length - activeNodesCnt);
1484
+ $('#clm-totalCcuLobby').text(data.getInt('ccuLobby'));
1485
+ $('#clm-totalCcuNodes').text(data.getInt('ccuNodes'));
1486
+ $('#clm-totalRooms').text(data.getInt('rooms'));
2207
1487
 
2208
- // Sessions
2209
- $('#dsh-detSessionsCurrent').text('Current: ' + (data.getInt('sSocket') + data.getInt('sHttp')));
2210
- $('#dsh-detSessionsMax').text('Max: ' + data.getInt('ccsMax'));
2211
- $('#dsh-detSessionsSocket').text('Socket: ' + data.getInt('sSocket'));
2212
- $('#dsh-detSessionsHttp').text('Http: ' + data.getInt('sHttp'));
1488
+ // Show lobby state
1489
+ this._showLobbyState(data.getBool('active'));
1490
+ }
1491
+
1492
+ else if (command == this.RESP_NODES_DATA)
1493
+ {
1494
+ let stats = data.getSFSArray('stats');
1495
+ let i = this._mainRangeDD.value();
1496
+ let intervalMillis = this.intervals[i].minutes * 60 * 1000;
2213
1497
 
2214
- // Users
2215
- $('#dsh-detUsersCurrent').text('Current: ' + (data.getInt('uSocket') + data.getInt('uHttp') + data.getInt('uNpc')));
2216
- $('#dsh-detUsersMax').text('Max: ' + data.getInt('ccuMax'));
2217
- $('#dsh-detUsersSocket').text('Socket: ' + data.getInt('uSocket'));
2218
- $('#dsh-detUsersHttp').text('Http: ' + data.getInt('uHttp'));
2219
- $('#dsh-detUsersNpc').text('Npc: ' + data.getInt('uNpc'));
1498
+ for (let i = 0; i < stats.size(); i++)
1499
+ {
1500
+ let nodeStats = stats.getSFSObject(i);
2220
1501
 
2221
- // Rooms
2222
- $('#dsh-detRooms').text(data.getInt('rTotal'));
2223
- $('#dsh-detRoomsRegular').text('Regular: ' + (data.getInt('rTotal') - data.getInt('rGame')));
2224
- $('#dsh-detRoomsGame').text('Game: ' + data.getInt('rGame'));
1502
+ // Get node id
1503
+ let id = nodeStats.getUtfString('id');
2225
1504
 
2226
- // Total data transfer
2227
- $('#dsh-detDataTransferOut').text('Out: ' + Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_1__["kBytesToSize"])(data.getLong('ntOut')));
2228
- $('#dsh-detDataTransferIn').text('In: ' + Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_1__["kBytesToSize"])(data.getLong('ntIn')));
1505
+ // Get charts item for node
1506
+ let item = this.querySelector('#clm-nodeMiniChartsContainer #node_' + id);
2229
1507
 
2230
- // Current data transfer rate
2231
- let obj = this._networkRTChart.getLastEntry();
1508
+ if (item)
1509
+ {
1510
+ item.addChartEntries('ccu', nodeStats.getSFSObject('ccu'), null, intervalMillis);
1511
+ item.addChartEntries('cpu', nodeStats.getSFSObject('cpu'), null, intervalMillis);
1512
+ item.addChartEntries('mem', nodeStats.getSFSObject('mem'), null, intervalMillis);
1513
+ item.addChartEntries('thd', nodeStats.getSFSObject('thd'), null, intervalMillis);
1514
+ item.addChartEntries('net', nodeStats.getSFSObject('netOut'), nodeStats.getSFSObject('netIn'), intervalMillis);
1515
+ }
1516
+ }
1517
+ }
2232
1518
 
2233
- if (obj == null)
2234
- obj = {outgoing: 0, incoming: 0};
1519
+ else if (command == this.RESP_CHART_DATA)
1520
+ {
1521
+ let chartData = data.getSFSObject('chart');
1522
+ let i = this._chartRangeDD.value();
1523
+ let intervalMillis = this.intervals[i].minutes * 60 * 1000;
2235
1524
 
2236
- $('#dsh-detTransferRateOut').text('Out: ' + Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_1__["kBytesToSize"])(obj.outgoing, 2, 'KB', '/s'));
2237
- $('#dsh-detTransferRateIn').text('In: ' + Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_1__["kBytesToSize"])(obj.incoming, 2, 'KB', '/s'));
1525
+ // Get node id and chart type
1526
+ let id = chartData.getUtfString('id');
1527
+ let type = chartData.getUtfString('type');
2238
1528
 
2239
- // Average data transfer rate over whole uptime
2240
- if (this._uptimeSecs > 0)
1529
+ if (this._chartInfo && this._chartInfo.id == id && this._chartInfo.type == type)
2241
1530
  {
2242
- const avgOut = Math.round(data.getLong('ntOut') / this._uptimeSecs * 100) / 100;
2243
- const avgIn = Math.round(data.getLong('ntIn') / this._uptimeSecs * 100) / 100;
1531
+ switch (type)
1532
+ {
1533
+ case 'net':
1534
+ this._addDetailChartEntries(chartData.getSFSObject('netOut'), chartData.getSFSObject('netIn'), intervalMillis);
1535
+ break;
2244
1536
 
2245
- $('#dsh-detAvgTransferRateOut').text('Out: ' + Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_1__["kBytesToSize"])(avgOut, 2, 'KB', '/s'));
2246
- $('#dsh-detAvgTransferRateIn').text('In: ' + Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_1__["kBytesToSize"])(avgIn, 2, 'KB', '/s'));
1537
+ default:
1538
+ this._addDetailChartEntries(chartData.getSFSObject(type), null, intervalMillis);
1539
+ }
2247
1540
  }
2248
-
2249
- // Dropped packets
2250
- const totalPacketsOut = data.getLong('pktOut');
2251
-
2252
- const totalDroppedTcpPacketsOut = data.getLong('pktOutDrop');
2253
- $('#dsh-detDroppedTcpPacketsOut').text(`Out TCP: ${totalDroppedTcpPacketsOut} (${Math.round(totalDroppedTcpPacketsOut / totalPacketsOut * 100)}%)`);
2254
-
2255
- const totalDroppedUdpPacketsOut = data.getLong('pktOutUdpDrop');
2256
- $('#dsh-detDroppedUdpPacketsOut').text(`Out UDP: ${totalDroppedUdpPacketsOut} (${Math.round(totalDroppedUdpPacketsOut / totalPacketsOut * 100)}%)`);
2257
-
2258
- const totalPacketsIn = data.getLong('pktIn');
2259
- const totalDroppedPacketsIn = data.getLong('pktInDrop');
2260
- $('#dsh-detDroppedPacketsIn').text(`In: ${totalDroppedPacketsIn} (${Math.round(totalDroppedPacketsIn / totalPacketsIn * 100)}%)`);
2261
-
2262
- // SYSTEM STATUS
2263
-
2264
- // Outgoing TCP messages queue
2265
- const outMsgQueue = data.getInt('outMsgQueue');
2266
- const outMsgQueueMax = data.getInt('outMsgQueueMax');
2267
- this._outTcpMsgQueueChart.addEntry(outMsgQueue, outMsgQueueMax);
2268
- this._tcpOutThreads = data.getInt('outMsgTh');
2269
- this._tcpOutLoad = this._outTcpMsgQueueChart.load;
2270
-
2271
- // Outgoing UDP messages queue
2272
- const outUdpMsgQueue = data.getInt('outUdpMsgQueue');
2273
- const outUdpMsgQueueMax = data.getInt('outUdpMsgQueueMax');
2274
- this._outUdpMsgQueueChart.addEntry(outUdpMsgQueue, outUdpMsgQueueMax);
2275
- this._udpOutThreads = data.getInt('outUdpMsgTh');
2276
- this._udpOutLoad = this._outUdpMsgQueueChart.load;
2277
-
2278
- this._updateOutMessagesQueueStatus();
2279
-
2280
- // System Controller requests queue
2281
- const sysCtrlQueue = data.getInt('sysCtrlQueue');
2282
- const sysCtrlQueueMax = data.getInt('sysCtrlQueueMax');
2283
- this._sysQueueChart.addEntry(sysCtrlQueue, sysCtrlQueueMax);
2284
- $('#dsh-systemQueueThreads').text(this._getQueueThreadsLabel(data.getInt('sysCtrlTh')));
2285
- $('#dsh-systemQueueLoad').text(this._getQueueLoadLabel(this._sysQueueChart.load));
2286
-
2287
- // Extension Controller requests queue
2288
- const extCtrlQueue = data.getInt('extCtrlQueue');
2289
- const extCtrlQueueMax = data.getInt('extCtrlQueueMax');
2290
- this._extQueueChart.addEntry(extCtrlQueue, extCtrlQueueMax);
2291
- $('#dsh-extensionQueueThreads').text(this._getQueueThreadsLabel(data.getInt('extCtrlTh')));
2292
- $('#dsh-extensionQueueLoad').text(this._getQueueLoadLabel(this._sysQueueChart.load));
2293
-
2294
- // Evaluate overall system workload
2295
- let sysWorkload = Math.round((outMsgQueue / outMsgQueueMax +
2296
- outUdpMsgQueue / outUdpMsgQueueMax +
2297
- sysCtrlQueue / sysCtrlQueueMax +
2298
- extCtrlQueue / extCtrlQueueMax) * 100 / 4);
2299
- if (sysWorkload > 100)
2300
- sysWorkload = 100;
2301
-
2302
- this._sysWorkloadChart.addEntry(sysWorkload);
2303
1541
  }
2304
1542
 
2305
- // Thread dump received
2306
- else if (command == this.RESP_THREAD_DUMP)
1543
+ else if (command == this.RESP_LOG_MESSAGES)
2307
1544
  {
2308
- // Enable button
2309
- $('#dsh-dumpThreadsBt').attr('disabled', false);
1545
+ let logEntries = data.getSFSArray('entries');
1546
+
1547
+ for (let e = 0; e < logEntries.size(); e++)
1548
+ {
1549
+ let logEntry = logEntries.getSFSObject(e);
1550
+
1551
+ let ele = {
1552
+ timestamp: kendo.toString(new Date(logEntry.getLong('time')), 'dd/MM/yyyy HH:mm:ss'),
1553
+ level: logEntry.getUtfString('level'),
1554
+ message: logEntry.getUtfString('msg'),
1555
+ };
2310
1556
 
2311
- // Set result
2312
- $('#dsh-threadDumpResult').text(data.getText('dump'));
1557
+ let ds = this._logGrid.dataSource;
1558
+ ds.add(ele);
2313
1559
 
2314
- // Display modal
2315
- $('#dsh-threadDumpModal').modal('show');
1560
+ // Check items limit
1561
+ while (ds.total() > this.MAX_LOG_SIZE)
1562
+ ds.remove(ds.at(0));
1563
+ }
2316
1564
  }
2317
1565
  }
2318
1566
 
@@ -2321,294 +1569,516 @@ class Dashboard extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
2321
1569
  this._uptimeSecs = values[3];
2322
1570
  this._uptimeSecs += (values[2] * 60);
2323
1571
  this._uptimeSecs += (values[1] * 60 * 60);
2324
- this._uptimeSecs += (values[0] * 24 * 60 * 60);
2325
1572
 
2326
- $('#dsh-uptimeDays').text( (values[0] <= 9 ? '00' : (values[0] <= 99 ? '0' : '')) + values[0] );
2327
- $('#dsh-uptimeHours').text( (values[1] <= 9 ? '0' : '') + values[1] );
2328
- $('#dsh-uptimeMinutes').text( (values[2] <= 9 ? '0' : '') + values[2] );
2329
- $('#dsh-uptimeSeconds').text( (values[3] <= 9 ? '0' : '') + values[3] );
1573
+ $('#clm-uptimeDays').text( (values[0] <= 9 ? '00' : (values[0] <= 99 ? '0' : '')) + values[0] );
1574
+ $('#clm-uptimeHours').text( (values[1] <= 9 ? '0' : '') + values[1] );
1575
+ $('#clm-uptimeMinutes').text( (values[2] <= 9 ? '0' : '') + values[2] );
2330
1576
  }
2331
1577
 
2332
1578
  //---------------------------------
2333
1579
  // UI EVENT LISTENERS
2334
1580
  //---------------------------------
2335
1581
 
2336
- _onUpdateIntervalChange()
1582
+ _onNodesGridChange(e, args)
2337
1583
  {
2338
- // Request data to server
2339
- this._requestData();
2340
- }
1584
+ let grid = e.sender;
1585
+ let items = grid.items();
2341
1586
 
2342
- _onPauseUpdateClick()
2343
- {
2344
- this._setChartUpdatePaused(true);
1587
+ this._selectedNodes = [];
1588
+ this._selectedActiveNodes = [];
1589
+
1590
+ for (let i of grid.select())
1591
+ {
1592
+ let dataItem = grid.dataItem(i);
1593
+ this._selectedNodes.push(dataItem['id']);
1594
+
1595
+ if (dataItem['active'])
1596
+ this._selectedActiveNodes.push(dataItem['id']);
1597
+ }
1598
+
1599
+ // Compare the list of selected nodes with the list of visible
1600
+ // chart rows, to show/hide the selected/deselected ones
1601
+ this._updateChartedNodes();
2345
1602
 
2346
- // Hide pause button and show play button
2347
- $('#dsh-pauseBt').addClass('hidden');
2348
- $('#dsh-playBt').removeClass('hidden');
1603
+ // Enable/disable button to deactivate selected active nodes
1604
+ this._updateDeactivateButton();
2349
1605
  }
2350
1606
 
2351
- _onPlayUpdateClick()
1607
+ _onNodesGridDataBound(e)
2352
1608
  {
2353
- this._setChartUpdatePaused(false);
1609
+ let grid = e.sender;
1610
+ let items = grid.items();
1611
+ let itemsToSelect = [];
1612
+ let self = this;
1613
+
1614
+ items.each(function (idx, row) {
1615
+ let dataItem = grid.dataItem(row);
1616
+ if (self._selectedNodes.includes(dataItem['id'])) {
1617
+ itemsToSelect.push(row);
1618
+ }
1619
+ });
1620
+
1621
+ e.sender.select(itemsToSelect);
1622
+
1623
+ //==================================================
1624
+
1625
+ // Hide group column and collapse icon
1626
+ $('#clm-nodesList .k-group-col, #clm-nodesList .k-group-cell').remove();
1627
+ let spanCells = $('#clm-nodesList .k-grouping-row').children('td');
1628
+ spanCells.attr('colspan', spanCells.attr('colspan') - 1);
1629
+ $('#clm-nodesList .k-icon.k-i-collapse').hide();
2354
1630
 
2355
- // Hide play button and show pause button
2356
- $('#dsh-pauseBt').removeClass('hidden');
2357
- $('#dsh-playBt').addClass('hidden');
1631
+ // Modify group label
1632
+ $('#clm-nodesList .k-grouping-row td p.k-reset').each(function( index ) {
1633
+ if ($(this).text() == 'active: true')
1634
+ $(this).text('Active nodes');
1635
+ else
1636
+ $(this).text('Inactive nodes');
1637
+ });
2358
1638
  }
2359
1639
 
2360
- _onResetChartsClick()
1640
+ _onMainRangeChange(e)
2361
1641
  {
2362
- // Reactivate realtime charts update
2363
- this._onPlayUpdateClick();
2364
-
2365
- // Reset realtime charts
2366
- this._cpuUsageChart.reset();
2367
- this._threadCountChart.reset();
2368
- this._memoryChart.reset();
2369
- this._networkRTChart.reset();
2370
- this._sysWorkloadChart.reset();
2371
- this._outTcpMsgQueueChart.reset();
2372
- this._outUdpMsgQueueChart.reset();
2373
- this._sysQueueChart.reset();
2374
- this._extQueueChart.reset();
1642
+ // Request nodes data to server
1643
+ this._requestNodesData();
2375
1644
  }
2376
1645
 
2377
- _redrawNetworkCharts()
1646
+ _onChartRangeChange(e)
2378
1647
  {
2379
- // Redraw charts
2380
- this._networkRTChart.redraw();
2381
- this._network24hChart.redraw();
2382
-
2383
- // Redraw time range slider
2384
- this._timeSlider.resize();
1648
+ // Request detail chart data to server
1649
+ this._requestDetailChartData();
2385
1650
  }
2386
1651
 
2387
- _redrawOutMsgCharts()
1652
+ _onRequestDataInterval()
2388
1653
  {
2389
- // Redraw charts
2390
- this._outTcpMsgQueueChart.redraw();
2391
- this._outUdpMsgQueueChart.redraw();
1654
+ // Request selected nodes data
1655
+ this._requestNodesData();
2392
1656
 
2393
- this._updateOutMessagesQueueStatus();
1657
+ // Request detail chart data
1658
+ this._requestDetailChartData();
2394
1659
  }
2395
1660
 
2396
- _onWindowResize()
1661
+ _requestNodesList()
2397
1662
  {
2398
- // Redraw all global charts
2399
- this._cpuUsageChart.redraw();
2400
- this._threadCountChart.redraw();
2401
- this._memoryChart.redraw();
2402
- this._redrawNetworkCharts();
2403
-
2404
- // Redraw all queue charts
2405
- this._sysWorkloadChart.redraw();
2406
- this._sysQueueChart.redraw();
2407
- this._extQueueChart.redraw();
2408
- this._redrawOutMsgCharts();
1663
+ // Clear previous request scheduling
1664
+ clearTimeout(this._requestNodesTimer);
1665
+
1666
+ // Check if connection is still available
1667
+ if (this.smartFox.isConnected)
1668
+ {
1669
+ // Send request to extension
1670
+ this.sendExtensionRequest(this.REQ_GET_NODES);
1671
+
1672
+ // Schedule next request
1673
+ this._requestNodesTimer = setTimeout($.proxy(this._requestNodesList, this), 5000); // Every 5 seconds
1674
+ }
2409
1675
  }
2410
1676
 
2411
- _onTimeRangeChange()
1677
+ _onMiniChartClick(e)
2412
1678
  {
2413
- let values = this._timeSlider.value();
1679
+ let nodeId = e.detail.node;
1680
+ let nodeDataItem = this._grid.dataSource.get(nodeId);
1681
+ let chartType = e.detail.type;
1682
+ let chartOptions = e.detail.options;
2414
1683
 
2415
- if (values[0] == values[1])
2416
- {
2417
- if (values[1] == -24)
2418
- values[1] = -23;
1684
+ // Save ref to charted node
1685
+ this._chartInfo = {
1686
+ id: nodeId,
1687
+ type: chartType
1688
+ };
2419
1689
 
2420
- values[0] = values[1] - 1;
1690
+ // Extract chart title from options
1691
+ $('#clm-chartModalTitle').text(chartOptions.title.text);
2421
1692
 
2422
- // Reset the time range slider value (we need to use setTimeout
2423
- // bacause doing it in the change event listener doesn't redraw the slider)
2424
- setTimeout($.proxy( function(values) { this._timeSlider.value(values); }, this), 10, values);
1693
+ if (nodeDataItem.alias)
1694
+ {
1695
+ $('#clm-chartNodeAlias').text(nodeDataItem.alias);
1696
+ $('#clm-chartNodeName').text(nodeDataItem.name);
1697
+ }
1698
+ else
1699
+ {
1700
+ $('#clm-chartNodeAlias').text(nodeDataItem.name);
1701
+ $('#clm-chartNodeName').hide();
2425
1702
  }
2426
1703
 
2427
- this._network24hChart.range = values;
2428
- }
1704
+ // Set secondary range dropdown to main range value
1705
+ let index = this._mainRangeDD.select();
1706
+ this._chartRangeDD.select(index);
2429
1707
 
2430
- _onUseHttpsForWsManagerChange()
2431
- {
2432
- const wsMan = this._wsManagerConfig;
1708
+ // Create chart tag
1709
+ $('#clm-nodeDetailChartContainer').append($('<div>', {'class': 'chart'}))
2433
1710
 
2434
- let url = ($('#dsh-useHttpsCheck').prop('checked') ? 'https' : 'http') + '://';
2435
- url += this.smartFox.config.host;
2436
- url += ':' + ($('#dsh-useHttpsCheck').prop('checked') ? wsMan.httpsPort : wsMan.httpPort);
2437
- url += '/manager/status';
1711
+ // Initialize chart
1712
+ this._getChartTag().kendoChart({
1713
+ transitions: false,
1714
+ chartArea: {
1715
+ background: 'transparent',
1716
+ margin: 0,
1717
+ padding:0
1718
+ },
1719
+ legend: {
1720
+ visible: false
1721
+ },
2438
1722
 
2439
- $('#dsh-toWsManagerBt').attr('href', url);
2440
- }
1723
+ seriesDefaults: {
1724
+ type: 'scatterLine',
1725
+ labels: {
1726
+ visible: false,
1727
+ format: '{0}',
1728
+ background: 'transparent'
1729
+ },
1730
+ missingValues: 'gap',
1731
+ markers: {
1732
+ visible: true,
1733
+ type: 'circle',
1734
+ size: 3,
1735
+ },
1736
+ },
1737
+ series: chartOptions.series,
1738
+ yAxis: chartOptions.yAxis,
1739
+ xAxis: {
1740
+ majorGridLines: {
1741
+ visible: false
1742
+ },
1743
+ majorTicks: {
1744
+ visible: true
1745
+ },
1746
+ labels: {
1747
+ visible: true,
1748
+ rotation: 0,
1749
+ template: '#: kendo.toString(new Date(value), "HH:mm") #'
1750
+ },
1751
+ },
1752
+ tooltip: chartOptions.tooltip
1753
+ }).data('kendoChart');
2441
1754
 
2442
- _onDumpThreadsClick()
2443
- {
2444
- // Disable button
2445
- $('#dsh-dumpThreadsBt').attr('disabled', true);
1755
+ // Clear chart
1756
+ this._getChartWidget().setDataSource(null);
2446
1757
 
2447
- // Send request to extension
2448
- this.sendExtensionRequest(this.REQ_DUMP_THREADS);
1758
+ // Display chart modal
1759
+ $('#clm-chartModal').modal('show');
1760
+
1761
+ // Request detail chart data to server
1762
+ this._requestDetailChartData();
2449
1763
  }
2450
1764
 
2451
- _onCopyThreadDumpClick()
1765
+ _onChartModalHidden(e)
2452
1766
  {
2453
- $('#dsh-threadDumpResult').attr('contenteditable', true);
2454
- $('#dsh-threadDumpResult').attr('spellcheck', false);
2455
- $('#dsh-threadDumpResult').focus();
2456
- document.execCommand('selectAll');
2457
- document.execCommand('copy');
2458
- window.getSelection().removeAllRanges();
2459
- $('#dsh-threadDumpResult').blur();
2460
- $('#dsh-threadDumpResult').attr('contenteditable', false);
1767
+ // Destroy chart
1768
+ this._chartInfo = null;
1769
+
1770
+ $('#clm-chartModalTitle').text('');
1771
+ $('#clm-chartNodeAlias').text('');
1772
+ $('#clm-chartNodeName').text('');
1773
+
1774
+ this._getChartWidget().destroy();
1775
+ this._getChartTag().remove();
2461
1776
  }
2462
1777
 
2463
- _onThreadDumpModalHidden()
1778
+ _requestOrchestrationLogs()
2464
1779
  {
2465
- // Clear modal content
2466
- $('#dsh-threadDumpResult').text('');
1780
+ // Build request parameters
1781
+ let params = new SFS2X.SFSObject();
1782
+ params.putLong('ts', this._lastLogsReqTimestamp);
1783
+
1784
+ // Send request to extension
1785
+ this.sendExtensionRequest(this.REQ_GET_LOG_MESSAGES, params);
1786
+
1787
+ // Update last request time
1788
+ this._lastLogsReqTimestamp = Date.now();
2467
1789
  }
2468
1790
 
2469
1791
  //------------------------------------
2470
1792
  // PRIVATE METHODS
2471
1793
  //------------------------------------
2472
1794
 
2473
- _enableWebServerManagerAccess()
1795
+ _updateChartedNodes()
2474
1796
  {
2475
- const wsMan = this._wsManagerConfig;
1797
+ // Get selected nodes not yet shown in the chart area
1798
+ let toShow = this._selectedNodes.filter(x => !this._chartedNodes.includes(x));
2476
1799
 
2477
- if (wsMan.hasAccess && (wsMan.httpEnabled || wsMan.httpsEnabled))
1800
+ // Get nodes shown in the chart area not in the selected list anymore
1801
+ let toHide = this._chartedNodes.filter(x => !this._selectedNodes.includes(x));
1802
+
1803
+ // Show nodes charts
1804
+ if (toShow.length > 0)
2478
1805
  {
2479
- // Hide alert
2480
- $('#dsh-wsManagerAlert').hide();
1806
+ //console.log("SHOWING CHARTS OF NODES: " + toShow)
1807
+ this._chartedNodes = [...this._chartedNodes, ...toShow]; // Merge arrays
1808
+
1809
+ // Display node charts
1810
+ for (let id of toShow)
1811
+ this._displayNodeChartsItem(id);
1812
+ }
2481
1813
 
2482
- // Enable button
2483
- $('#dsh-toWsManagerBt').attr('disabled', false);
1814
+ // Hide nodes charts
1815
+ if (toHide.length > 0)
1816
+ {
1817
+ //console.log("HIDING CHARTS OF NODES: " + toHide)
1818
+ this._chartedNodes = this._chartedNodes.filter(x => !toHide.includes(x));
2484
1819
 
2485
- // Set checkbox
2486
- $('#dsh-useHttpsCheck').prop('checked', wsMan.httpsEnabled);
2487
- $('#dsh-useHttpsCheck').attr('disabled', !wsMan.httpEnabled || !wsMan.httpsEnabled);
1820
+ // Remove node charts
1821
+ for (let id of toHide)
1822
+ {
1823
+ this._removeNodeChartsItem(id);
2488
1824
 
2489
- // Generate link
2490
- this._onUseHttpsForWsManagerChange();
1825
+ // Remove detail chart if visible
1826
+ if (this._chartInfo && id == this._chartInfo.id)
1827
+ $('#clm-chartModal').modal('hide');
1828
+ }
2491
1829
  }
2492
- else
2493
- {
2494
- // Show alert
2495
- $('#dsh-wsManagerAlert').show();
2496
1830
 
2497
- if (!wsMan.hasAccess)
2498
- $('#dsh-wsManagerAlert').html('Access to Tomcat Manager console requires at least one user to be defined in <em>Web Server</em> tab of <strong>Server Configurator</strong> module.');
1831
+ // Show/hide interval dropdown
1832
+ if (toShow.length > 0 || toHide.length > 0)
1833
+ {
1834
+ if (this._chartedNodes.length > 0)
1835
+ $('#clm-mainRangeContainer').show();
2499
1836
  else
2500
- $('#dsh-wsManagerAlert').html('Access to Tomcat Manager console requires either HTTP or HTTPS to be enabled in <em>Web Server</em> tab of <strong>Server Configurator</strong> module.');
1837
+ $('#clm-mainRangeContainer').hide();
1838
+ }
2501
1839
 
2502
- // Disable button
2503
- $('#dsh-toWsManagerBt').attr('disabled', true);
1840
+ // Request charts data for newly selected nodes
1841
+ // NOTE: we have to use a timeout as a workaround to give charts time to be rendered before drawing them, or they will exceed their container's width
1842
+ if (toShow.length > 0)
1843
+ setTimeout($.proxy(this._requestNodesData, this), 20, toShow);
1844
+ }
1845
+
1846
+ _getTimeSinceJoinTemplate(dataItem)
1847
+ {
1848
+ let now = moment__WEBPACK_IMPORTED_MODULE_1__();
1849
+ let joinTime = moment__WEBPACK_IMPORTED_MODULE_1__(dataItem['joinTime']);
1850
+
1851
+ let diffDays = now.diff(joinTime, 'days');
1852
+ let diffHours = now.diff(joinTime, 'hours') - (diffDays * 24);
1853
+ let diffMinutes = now.diff(joinTime, 'minutes') - (((diffDays * 24) + diffHours) * 60);
1854
+
1855
+ return `<span>${diffDays}d ${diffHours}h ${diffMinutes}m<span>`;
1856
+ }
1857
+
1858
+ _getHealthTemplate(dataItem)
1859
+ {
1860
+ let style = 'text-success';
1861
+
1862
+ if (!dataItem['health'])
1863
+ style = 'text-danger';
1864
+
1865
+ return `<span class="${style}"><i class="fas fa-circle"></i></span>`;
1866
+ }
1867
+
1868
+ _getRecyclableTemplate(dataItem)
1869
+ {
1870
+ let style = dataItem['recyclable'] ? 'text-success' : 'text-light';
1871
+ return `<span class="${style}"><i class="fas fa-circle"></i></span>`;
1872
+ }
1873
+
1874
+ _getTerminableTemplate(dataItem)
1875
+ {
1876
+ let style = dataItem['terminable'] ? 'text-success' : 'text-light';
1877
+ return `<span class="${style}"><i class="fas fa-circle"></i></span>`;
1878
+ }
2504
1879
 
2505
- // Disable checkbox
2506
- $('#dsh-useHttpsCheck').attr('checked', wsMan.httpsEnabled);
2507
- $('#dsh-useHttpsCheck').attr('disabled', true);
1880
+ _showLobbyState(isActive)
1881
+ {
1882
+ if (isActive)
1883
+ {
1884
+ $('#clm-lobbyState .active').show();
1885
+ $('#clm-lobbyState .inactive').hide();
1886
+ }
1887
+ else
1888
+ {
1889
+ $('#clm-lobbyState .active').hide();
1890
+ $('#clm-lobbyState .inactive').show();
2508
1891
  }
1892
+
1893
+ $('#clm-lobbyState').show();
1894
+
1895
+ // Enable/disable scale-up button
1896
+ $('#clm-scaleUpBt').prop('disabled', !isActive);
2509
1897
  }
2510
1898
 
2511
- /**
2512
- * Build the polling request to be sent to the server.
2513
- */
2514
- _requestData(getHistory = false)
1899
+ _requestNodesData(nodes = null)
2515
1900
  {
2516
- // Clear previous request scheduling
2517
- clearTimeout(this._requestTimer);
1901
+ if (nodes == null)
1902
+ nodes = this._chartedNodes;
2518
1903
 
2519
- // Check if connection is still available
2520
- if (this.smartFox.isConnected)
1904
+ //console.log("REQUESTING DATA FOR NODES " + nodes + " (last " + this.intervals[this._mainRangeDD.value()].minutes + " minutes)")
1905
+
1906
+ if (nodes.length > 0 && this.smartFox.isConnected)
2521
1907
  {
1908
+ let i = this._mainRangeDD.value();
1909
+ let intervalMillis = this.intervals[i].minutes * 60 * 1000;
1910
+ let dataPoints = this.intervals[i].points1;
1911
+
1912
+ // List nodes
1913
+ let list = new SFS2X.SFSArray();
1914
+
1915
+ for (let nodeId of nodes)
1916
+ {
1917
+ let obj = new SFS2X.SFSObject();
1918
+ obj.putUtfString('id', nodeId);
1919
+ obj.putLong('int', intervalMillis);
1920
+ obj.putInt('pts', dataPoints);
1921
+
1922
+ list.addSFSObject(obj);
1923
+ }
1924
+
2522
1925
  // Build request parameters
2523
1926
  let params = new SFS2X.SFSObject();
1927
+ params.putSFSArray('nodes', list);
2524
1928
 
2525
- if (getHistory)
2526
- params.putBool('history', true);
1929
+ // Send request to Extension
1930
+ this.sendExtensionRequest(this.REQ_GET_NODES_DATA, params);
1931
+ }
1932
+ }
2527
1933
 
2528
- // Send request to extension
2529
- this.sendExtensionRequest(this.REQ_GET_DATA, params);
1934
+ _requestDetailChartData()
1935
+ {
1936
+ if (this._chartInfo)
1937
+ {
1938
+ let i = this._chartRangeDD.value();
2530
1939
 
2531
- // Schedule next request
2532
- this._requestTimer = setTimeout($.proxy(this._requestData, this), Number(this._intervalDropDown.value()) * 1000);
1940
+ let params = new SFS2X.SFSObject();
1941
+ params.putUtfString('id', this._chartInfo.id);
1942
+ params.putUtfString('type', this._chartInfo.type);
1943
+ params.putLong('int', this.intervals[i].minutes * 60 * 1000);
1944
+ params.putInt('pts', this.intervals[i].points2);
1945
+
1946
+ // Send request to Extension
1947
+ this.sendExtensionRequest(this.REQ_GET_CHART_DATA, params);
2533
1948
  }
2534
1949
  }
2535
1950
 
2536
- _getMemObject(bytes)
1951
+ _removeNodeChartsItem(nodeId)
2537
1952
  {
2538
- return {
2539
- data: bytes,
2540
- label: Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_1__["bytesToSize"])(bytes)
2541
- };
1953
+ let element = this.querySelector('#clm-nodeMiniChartsContainer #node_' + nodeId);
1954
+
1955
+ // Destroy element
1956
+ element.destroy();
1957
+
1958
+ // Remove element from container
1959
+ this.querySelector('#clm-nodeMiniChartsContainer').removeChild(element);
1960
+ }
1961
+
1962
+ _displayNodeChartsItem(nodeId)
1963
+ {
1964
+ let nodeDataItem = this._grid.dataSource.get(nodeId);
1965
+
1966
+ // Create element
1967
+ let element = new _components_module_specific_cluster_monitor_node_mini_charts__WEBPACK_IMPORTED_MODULE_3__["NodeMiniCharts"](nodeDataItem['id'], nodeDataItem['alias'], nodeDataItem['name']);
1968
+
1969
+ // Append element to container
1970
+ this.querySelector('#clm-nodeMiniChartsContainer').appendChild(element);
1971
+ }
1972
+
1973
+ _getChartTag()
1974
+ {
1975
+ return $('#clm-chartModal .chart');
2542
1976
  }
2543
1977
 
2544
- _setChartUpdatePaused(paused)
1978
+ _getChartWidget()
2545
1979
  {
2546
- // Pause/reactivate realtime charts
2547
- this._cpuUsageChart.paused = paused;
2548
- this._threadCountChart.paused = paused;
2549
- this._memoryChart.paused = paused;
2550
- this._networkRTChart.paused = paused;
2551
- this._sysWorkloadChart.paused = paused;
2552
- this._outTcpMsgQueueChart.paused = paused;
2553
- this._sysQueueChart.paused = paused;
2554
- this._extQueueChart.paused = paused;
1980
+ return this._getChartTag().data('kendoChart');
2555
1981
  }
2556
1982
 
2557
- _getThreadsGridDataSource(items, sort)
1983
+ _addDetailChartEntries(data, data1, intervalMillis)
2558
1984
  {
2559
- if (!items)
2560
- items = '';
1985
+ let lastTimestamp = data.getLong('last');
1986
+ let values = data.getLongArray('data');
1987
+ let values1 = (data1 != null ? data1.getLongArray('data') : null);
1988
+ let chartWidget = this._getChartWidget();
1989
+
1990
+ // Divide interval by the number of data points to calculate their timestamps
1991
+ let sliceMillis = Math.round(intervalMillis / values.length);
2561
1992
 
2562
- if (!sort)
1993
+ let ds = new kendo.data.DataSource();
1994
+ let firstTimestamp = lastTimestamp - intervalMillis;
1995
+
1996
+ for (let i = 0; i < values.length; i++)
2563
1997
  {
2564
- sort = {
2565
- field: 'cpuTime',
2566
- dir: 'desc'
1998
+ let timestamp = firstTimestamp + (sliceMillis * i);
1999
+
2000
+ let value = values[i] < 0 ? null : values[i];
2001
+ let value1 = values1 ? (values1[i] < 0 ? null : values1[i]) : null;
2002
+
2003
+ let entry = {
2004
+ ts: timestamp,
2005
+ val: value,
2006
+ val1: value1,
2567
2007
  };
2008
+
2009
+ ds.add(entry);
2568
2010
  }
2569
2011
 
2570
- return new kendo.data.DataSource({
2571
- schema: {
2572
- model: {
2573
- id: 'id'
2574
- }
2575
- },
2576
- sort: sort,
2577
- data: items
2578
- });
2012
+ // Set chart's x-axis limits
2013
+ chartWidget.options.xAxis.min = firstTimestamp;
2014
+ chartWidget.options.xAxis.max = lastTimestamp;
2015
+
2016
+ chartWidget.setDataSource(ds);
2579
2017
  }
2580
2018
 
2581
- _getQueueThreadsLabel(threadsNum)
2019
+ _updateDeactivateButton()
2582
2020
  {
2583
- return `Threads: ${threadsNum}`;
2021
+ let cnt = this._selectedActiveNodes.length;
2022
+ let txt = (cnt > 0 ? cnt : '') + ' node' + (cnt != 1 ? 's' : '');
2023
+
2024
+ $('#clm-deactivateBt').prop('disabled', cnt == 0);
2025
+ $('#clm-deactivateNodesNum').text(txt);
2584
2026
  }
2585
2027
 
2586
- _getQueueLoadLabel(load)
2028
+ _onDeactivateBtClick()
2587
2029
  {
2588
- return `Avg. messages: ${load}`;
2030
+ this.shellCtrl.showConfirmWarning(`Are you sure you want to deactivate the selected active node${this._selectedActiveNodes.length > 1 ? 's' : ''}? This operation is irreversible.`, $.proxy(this._onDeactivateNodesConfirm, this));
2589
2031
  }
2590
2032
 
2591
- _updateOutMessagesQueueStatus()
2033
+ _onDeactivateNodesConfirm()
2592
2034
  {
2593
- let threadsStr = this._getQueueThreadsLabel('--');
2594
- let loadStr = this._getQueueLoadLabel('--');
2595
-
2596
- if ($('#dsh-tcpPill').hasClass('active'))
2035
+ if (this._selectedActiveNodes.length > 0 && this.smartFox.isConnected)
2597
2036
  {
2598
- threadsStr = this._getQueueThreadsLabel(this._tcpOutThreads);
2599
- loadStr = this._getQueueLoadLabel(this._tcpOutLoad);
2037
+ let params = new SFS2X.SFSObject();
2038
+ params.putUtfStringArray('nodes', this._selectedActiveNodes);
2039
+
2040
+ this.sendExtensionRequest(this.REQ_DEACTIVATE_NODES, params);
2600
2041
  }
2042
+ }
2043
+
2044
+ _onScaleUpBtClick()
2045
+ {
2046
+ // Display scale-up modal
2047
+ $('#clm-scaleUpModal').modal('show');
2048
+ }
2601
2049
 
2602
- if ($('#dsh-udpPill').hasClass('active'))
2050
+ _onScaleUpConfirmBtClick()
2051
+ {
2052
+ if (this._scaleUpValidator.validate())
2603
2053
  {
2604
- threadsStr = this._getQueueThreadsLabel(this._udpOutThreads);
2605
- loadStr = this._getQueueLoadLabel(this._udpOutLoad);
2054
+ // Retrieve scale-up details
2055
+ let params = new SFS2X.SFSObject();
2056
+ params.putInt('num', this._numNodesIn.value());
2057
+
2058
+ // Send scale-up request to server
2059
+ this.sendExtensionRequest(this.REQ_SCALE_UP, params);
2060
+
2061
+ // Hide modal
2062
+ $('#clm-scaleUpModal').modal('hide');
2606
2063
  }
2064
+ }
2065
+
2066
+ _onScaleUpModalHidden(e)
2067
+ {
2068
+ // Reset validator
2069
+ this._scaleUpValidator.hideMessages();
2070
+
2071
+ // The method above doesn't remove the k-invalid classes and aria-invalid="true" attributes from inputs
2072
+ // Let's do it manually
2073
+ $('#clm-scaleUpForm .k-invalid').removeClass('k-invalid');
2074
+ $('#clm-scaleUpForm [aria-invalid="true"]').removeAttr('aria-invalid');
2607
2075
 
2608
- $('#dsh-outgoingMessagesQueueThreads').text(threadsStr);
2609
- $('#dsh-outgoingMessagesQueueLoad').text(loadStr);
2076
+ // Reset scale-up form
2077
+ this._numNodesIn.value(1);
2610
2078
  }
2611
2079
 
2080
+
2081
+
2612
2082
  //---------------------------------
2613
2083
  // PRIVATE GETTERS
2614
2084
  //---------------------------------
@@ -2621,4 +2091,4 @@ class Dashboard extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
2621
2091
  /***/ })
2622
2092
 
2623
2093
  }]);
2624
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtNS5idW5kbGUuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL2NoYXJ0cy9iYXNlLWNoYXJ0LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvY2hhcnRzL2NoYXJ0LXV0aWxzLmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvY2hhcnRzL2NwdS11c2FnZS1jaGFydC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL2NoYXJ0cy9tZW1vcnktY2hhcnQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy9jaGFydHMvbmV0d29yay0yNGgtY2hhcnQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy9jaGFydHMvbmV0d29yay1yZWFsdGltZS1jaGFydC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL2NoYXJ0cy9zeXN0ZW0tcXVldWUtY2hhcnQuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy9jaGFydHMvc3lzdGVtLXdvcmtsb2FkLWNoYXJ0LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvY2hhcnRzL3RocmVhZC1jb3VudC1jaGFydC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9tb2R1bGVzL2Rhc2hib2FyZC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgY2xhc3MgQmFzZUNoYXJ0IGV4dGVuZHMgSFRNTEVsZW1lbnRcbntcblx0Y29uc3RydWN0b3IobWF4VmFsdWVzKVxuXHR7XG5cdCAgICBzdXBlcigpO1xuXG5cdFx0dGhpcy5fbWF4VmFsdWVzID0gbWF4VmFsdWVzO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZVxuXHRcdHRoaXMuX2luaXRpYWxpemUoKTtcblx0fVxuXG5cdC8vIENhbiBiZSBvdmVycmlkZGVuXG5cdF9pbml0aWFsaXplKClcblx0e1xuXHRcdC8vIENyZWF0ZSBjaGFydCBodG1sXG5cdFx0bGV0IGNoYXJ0SHRtbCA9ICQoJzxkaXY+Jyk7XG5cdFx0JCh0aGlzKS5hcHBlbmQoY2hhcnRIdG1sKTtcblxuXHRcdHRoaXMuX2NoYXJ0V2lkZ2V0ID0gdGhpcy5faW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbCk7XG5cblx0XHQvLyBSZXNldCBkYXRhIHNvdXJjZVxuXHRcdHRoaXMucmVzZXQoKTtcblx0fVxuXG5cdC8vIE1VU1QgQkUgT1ZFUlJJRERFTlxuXHRfaW5pdENoYXJ0V2lkZ2V0KClcblx0e1xuXHRcdHRocm93IG5ldyBFcnJvcignQ2hhcnQgd2lkZ2V0IG11c3QgYmUgaW5pdGlhbGl6ZWQhJylcblx0fVxuXG5cdHNldCBwYXVzZWQodmFsdWUpXG5cdHtcblx0XHR0aGlzLmlzUGF1c2VkID0gdmFsdWU7XG5cdFx0dGhpcy5fb25QYXVzZUNoYW5nZSgpO1xuXHR9XG5cblx0Z2V0IHBhdXNlZCgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5pc1BhdXNlZDtcblx0fVxuXG5cdHJlc2V0KClcblx0e1xuXHRcdHRoaXMuX2NoYXJ0V2lkZ2V0LnNldERhdGFTb3VyY2UoW10pO1xuXHR9XG5cblx0cmVkcmF3KClcblx0e1xuXHRcdHRoaXMuX2NoYXJ0V2lkZ2V0LnJlZHJhdygpO1xuXHR9XG5cblx0Z2V0TGFzdEVudHJ5KClcblx0e1xuXHRcdGxldCBkcztcblxuXHRcdGlmICh0aGlzLmlzUGF1c2VkKVxuXHRcdFx0ZHMgPSB0aGlzLl90ZW1wRFM7XG5cdFx0ZWxzZVxuXHRcdFx0ZHMgPSB0aGlzLl9kYXRhU291cmNlO1xuXG5cdFx0aWYgKGRzICE9IG51bGwgJiYgZHMudG90YWwoKSA+IDApXG5cdFx0XHRyZXR1cm4gZHMuYXQoZHMudG90YWwoKSAtIDEpO1xuXHRcdGVsc2Vcblx0XHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0X2FkZEVudHJ5KG5ld0VudHJ5KVxuXHR7XG5cdFx0aWYgKHRoaXMuaXNQYXVzZWQpXG5cdFx0e1xuXHRcdFx0aWYgKHRoaXMuX3RlbXBEUyA9PSBudWxsKVxuXHRcdFx0XHR0aGlzLl90ZW1wRFMgPSBuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKCk7XG5cblx0XHRcdC8vIFN0b3JlIG5ldyB2YWx1ZSBpbiBhIHRlbXBvcmFyeSBhcnJheVxuXHRcdFx0dGhpcy5fdGVtcERTLmFkZChuZXdFbnRyeSk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRsZXQgZHMgPSB0aGlzLl9kYXRhU291cmNlO1xuXG5cdFx0XHRpZiAodGhpcy5fdGVtcERTICE9IG51bGwpXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENvbmNhdGVuYXRlIHRlbXBvcmFyeSBlbnRyaWVzIHRvIGFjdHVhbCBkYXRhIHNvdXJjZVxuXHRcdFx0XHRsZXQgbmV3QXJyID0gJC5tZXJnZShkcy5kYXRhKCksIHRoaXMuX3RlbXBEUy5kYXRhKCkpO1xuXG5cdFx0XHRcdC8vIFJlbW92ZSB2YWx1ZXMgZXhjZWVkaW5nIE1BWF9WQUxVRVNcblx0XHRcdFx0aWYgKG5ld0Fyci5sZW5ndGggPiB0aGlzLl9tYXhWYWx1ZXMpXG5cdFx0XHRcdFx0bmV3QXJyLnNwbGljZSgwLCBuZXdBcnIubGVuZ3RoIC0gdGhpcy5fbWF4VmFsdWVzKVxuXG5cdFx0XHRcdC8vIENyZWF0ZSBuZXcgZGF0YXNvdXJjZVxuXHRcdFx0XHRsZXQgbmV3RFMgPSBuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKHtkYXRhOiBuZXdBcnJ9KVxuXG5cdFx0XHRcdC8vIEFzc2lnbiBuZXcgZGF0YSBzb3VyY2UgdG8gY2hhcnRcblx0XHRcdFx0dGhpcy5fY2hhcnRXaWRnZXQuc2V0RGF0YVNvdXJjZShuZXdEUyk7XG5cblx0XHRcdFx0Ly8gUmVtb3ZlIHRlbXBvcmFyeSBhcnJheVxuXHRcdFx0XHR0aGlzLl90ZW1wRFMgPSBudWxsO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBZGQgbmV3IGVudHJ5XG5cdFx0XHRkcy5hZGQobmV3RW50cnkpO1xuXG5cdFx0XHQvLyBSZW1vdmUgZmlyc3QgaXRlbSBpZiBuZWVkZWRcblx0XHRcdGlmIChkcy50b3RhbCgpID4gdGhpcy5fbWF4VmFsdWVzKVxuXHRcdFx0XHRkcy5yZW1vdmUoZHMuYXQoMCkpO1xuXHRcdH1cblx0fVxuXG5cdGdldCBfZGF0YVNvdXJjZSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fY2hhcnRXaWRnZXQuZGF0YVNvdXJjZTtcblx0fVxuXG5cdF9vblBhdXNlQ2hhbmdlKClcblx0e1xuXHRcdC8vIE5vdGhpbmcgdG8gZG8sIHNob3VsZCBiZSBvdmVycmlkZGVuXG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdiYXNlLWNoYXJ0JykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2Jhc2UtY2hhcnQnLCBCYXNlQ2hhcnQpO1xuIiwiaW1wb3J0IHtieXRlc1RvU2l6ZSwga0J5dGVzVG9TaXplfSBmcm9tICcuLi8uLi91dGlscy91dGlsaXRpZXMnO1xuXG5leHBvcnQgZnVuY3Rpb24gZ2V0Rm9ybWF0dGVkRGF0ZVRpbWUoZGF0ZSwgZm9ybWF0ID0gJ2RkIE1NTSBISDptbTpzcycpXG57XG5cdHJldHVybiBrZW5kby50b1N0cmluZyhkYXRlLCBmb3JtYXQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzaWNTaGFyZWRUZW1wbGF0ZSh2YWx1ZUZvcm1hdCA9ICd7MH0nKSB7XG5cdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0PGRpdiBjbGFzcz1cImNoYXJ0LXRvb2x0aXAtY2F0ZWdvcnlcIj48c3Ryb25nPiM6IGNhdGVnb3J5ICM8L3N0cm9uZz48L2Rpdj5cblx0XHQjIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7ICNcblx0XHQ8ZGl2PlxuXHRcdFx0PGkgY2xhc3M9XCJmYXMgZmEtc3F1YXJlXCIgc3R5bGU9XCJjb2xvcjogIzogcG9pbnRzW2ldLmNvbG9yICMgXCI+PC9pPlxuXHRcdFx0IzogcG9pbnRzW2ldLnNlcmllcy5uYW1lIyA6ICM6IGtlbmRvLmZvcm1hdCgnJHt2YWx1ZUZvcm1hdH0nLCBwb2ludHNbaV0udmFsdWUpICNcblx0XHQ8L2Rpdj5cblx0XHQjIH0gI1xuXHRgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE1lbW9yeVNoYXJlZFRlbXBsYXRlKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRkYXRhSXRlbS5ieXRlc1RvU2l6ZSA9IGJ5dGVzVG9TaXplOyAvLyBQYXNzIGJ5dGVzVG9TaXplIHV0aWxpdHkgZnVuY3Rpb24gdG8gdGVtcGxhdGVcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0PGRpdiBjbGFzcz1cImNoYXJ0LXRvb2x0aXAtY2F0ZWdvcnlcIj48c3Ryb25nPiM6IGNhdGVnb3J5ICM8L3N0cm9uZz48L2Rpdj5cblx0XHRcdCMgZm9yICh2YXIgaSA9IDA7IGkgPCBwb2ludHMubGVuZ3RoOyBpKyspIHsgI1xuXHRcdFx0PGRpdj5cblx0XHRcdFx0PGkgY2xhc3M9XCJmYXMgZmEtc3F1YXJlXCIgc3R5bGU9XCJjb2xvcjogIzogcG9pbnRzW2ldLmNvbG9yICMgXCI+PC9pPlxuXHRcdFx0XHQjOiBwb2ludHNbaV0uc2VyaWVzLm5hbWUjIDogIzogYnl0ZXNUb1NpemUocG9pbnRzW2ldLnZhbHVlKSAjXG5cdFx0XHQ8L2Rpdj5cblx0XHRcdCMgfSAjXG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TWVtb3J5VmFsdWVBeGlzTGFiZWxUZW1wbGF0ZSgpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0ZGF0YUl0ZW0uYnl0ZXNUb1NpemUgPSBieXRlc1RvU2l6ZTsgLy8gUGFzcyBieXRlc1RvU2l6ZSB1dGlsaXR5IGZ1bmN0aW9uIHRvIHRlbXBsYXRlXG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdCM6IGJ5dGVzVG9TaXplKHZhbHVlKSAjXG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV0d29ya1NoYXJlZFRlbXBsYXRlKGNhdGVnb3J5Rm9ybWF0ID0gJ2RkIE1NTSBISDptbTpzcycpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0ZGF0YUl0ZW0ua0J5dGVzVG9TaXplID0ga0J5dGVzVG9TaXplOyAvLyBQYXNzIGtCeXRlc1RvU2l6ZSB1dGlsaXR5IGZ1bmN0aW9uIHRvIHRlbXBsYXRlXG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdDxkaXYgY2xhc3M9XCJjaGFydC10b29sdGlwLWNhdGVnb3J5XCI+PHN0cm9uZz4jOiBrZW5kby50b1N0cmluZyhjYXRlZ29yeSwgJyR7Y2F0ZWdvcnlGb3JtYXR9JykgIzwvc3Ryb25nPjwvZGl2PlxuXHRcdFx0IyBmb3IgKHZhciBpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykgeyAjXG5cdFx0XHQ8ZGl2PlxuXHRcdFx0XHQ8aSBjbGFzcz1cImZhcyBmYS1zcXVhcmVcIiBzdHlsZT1cImNvbG9yOiAjOiBwb2ludHNbaV0uY29sb3IgIyBcIj48L2k+XG5cdFx0XHRcdCM6IHBvaW50c1tpXS5zZXJpZXMubmFtZSMgOiAjOiBrQnl0ZXNUb1NpemUocG9pbnRzW2ldLnZhbHVlLCAxLCAnJywgJy9zJykgI1xuXHRcdFx0PC9kaXY+XG5cdFx0XHQjIH0gI1xuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ldHdvcmtWYWx1ZUF4aXNMYWJlbFRlbXBsYXRlKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRkYXRhSXRlbS5rQnl0ZXNUb1NpemUgPSBrQnl0ZXNUb1NpemU7IC8vIFBhc3Mga0J5dGVzVG9TaXplIHV0aWxpdHkgZnVuY3Rpb24gdG8gdGVtcGxhdGVcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0Izoga0J5dGVzVG9TaXplKHZhbHVlLCAxLCAnJywgJy9zJykgI1xuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFVzZXJDb3VudFNoYXJlZFRlbXBsYXRlKGNhdGVnb3J5Rm9ybWF0ID0gJ2RkIE1NTSBISDptbTpzcycpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdDxkaXYgY2xhc3M9XCJjaGFydC10b29sdGlwLWNhdGVnb3J5XCI+PHN0cm9uZz4jOiBrZW5kby50b1N0cmluZyhjYXRlZ29yeSwgJyR7Y2F0ZWdvcnlGb3JtYXR9JykgIzwvc3Ryb25nPjwvZGl2PlxuXHRcdFx0IyBmb3IgKHZhciBpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykgeyAjXG5cdFx0XHQ8ZGl2PlxuXHRcdFx0XHQ8aSBjbGFzcz1cImZhcyBmYS1zcXVhcmVcIiBzdHlsZT1cImNvbG9yOiAjOiBwb2ludHNbaV0uY29sb3IgIyBcIj48L2k+XG5cdFx0XHRcdCM6IHBvaW50c1tpXS5zZXJpZXMubmFtZSMgOiAjOiBwb2ludHNbaV0udmFsdWUgI1xuXHRcdFx0PC9kaXY+XG5cdFx0XHQjIH0gI1xuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFRpbWVSYW5nZVRvb2x0aXBUZW1wbGF0ZSgpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0ZGF0YUl0ZW0uZ2V0VG9vbHRpcFN0cmluZyA9IGZ1bmN0aW9uKHYxLCB2Mikge1xuXHRcdFx0aWYgKHYxID09IHYyKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAodjIgPT0gLTI0KVxuXHRcdFx0XHRcdHYyID0gLTIzO1xuXG5cdFx0XHRcdHYxID0gdjIgLSAxO1xuXHRcdFx0fVxuXG5cdFx0XHRsZXQgc3RhcnQgPSBNYXRoLmFicyh2MSk7XG5cdFx0XHRsZXQgZW5kID0gTWF0aC5hYnModjIpO1xuXG5cdFx0XHRyZXR1cm4gYEZyb20gJHtzdGFydH0gaG91ciR7c3RhcnQgIT0gMSA/ICdzJyA6ICcnfSBhZ28gdG8gJHtlbmQgPiAwID8gKCd0byAnICsgZW5kICsgJyBob3VyJyArIChlbmQgIT0gMSA/ICdzJyA6ICcnKSArICcgYWdvJykgOiAnbm93J31gO1xuXHRcdH07IC8vIFBhc3MgdXRpbGl0eSBmdW5jdGlvbiB0byB0ZW1wbGF0ZVxuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQjOiBnZXRUb29sdGlwU3RyaW5nKHNlbGVjdGlvblN0YXJ0LCBzZWxlY3Rpb25FbmQpICNcblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRXUkJ5dGVzTGFiZWxUZW1wbGF0ZSgpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdCM6IHZhbHVlICMgIzogZGF0YUl0ZW0udW5pdCAjXG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuIiwiaW1wb3J0IHtCYXNlQ2hhcnR9IGZyb20gJy4vYmFzZS1jaGFydCc7XG5cbmltcG9ydCB7Z2V0QmFzaWNTaGFyZWRUZW1wbGF0ZSwgZ2V0Rm9ybWF0dGVkRGF0ZVRpbWV9IGZyb20gJy4vY2hhcnQtdXRpbHMnO1xuXG5leHBvcnQgY2xhc3MgQ3B1VXNhZ2VDaGFydCBleHRlbmRzIEJhc2VDaGFydFxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKDEyMCk7XG5cdH1cblxuXHRfaW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbClcblx0e1xuXHRcdHJldHVybiBjaGFydEh0bWwua2VuZG9DaGFydCh7XG5cdFx0XHR0cmFuc2l0aW9uczogZmFsc2UsXG5cdFx0XHRjaGFydEFyZWE6IHtcblx0XHRcdFx0aGVpZ2h0OiAxMjBcblx0XHRcdH0sXG5cdCAgICAgICAgbGVnZW5kOiB7XG5cdCAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXNEZWZhdWx0czoge1xuXHQgICAgICAgICAgICB0eXBlOiAnYXJlYScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0lJyxcblx0ICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCdcblx0ICAgICAgICAgICAgfVxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRuYW1lOiAnU3lzdGVtJyxcblx0XHQgICAgICAgICAgICBmaWVsZDogJ3N5c3RlbUxvYWQnLFxuXHRcdCAgICAgICAgICAgIGNhdGVnb3J5RmllbGQ6ICd0aW1lJyxcblx0XHRcdFx0XHRjb2xvcjogdGhpcy5zeXN0ZW1Db2xvcixcblx0XHRcdFx0XHRsaW5lOiB7XG5cdFx0XHRcdFx0XHR3aWR0aDogMlxuXHRcdFx0XHRcdH1cblx0XHQgICAgICAgIH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRuYW1lOiAnUHJvY2VzcycsXG5cdFx0XHRcdFx0ZmllbGQ6ICdwcm9jZXNzTG9hZCcsXG5cdFx0XHRcdFx0Y2F0ZWdvcnlGaWVsZDogJ3RpbWUnLFxuXHRcdFx0XHRcdGNvbG9yOiB0aGlzLnByb2Nlc3NDb2xvcixcblx0XHRcdFx0XHRsaW5lOiB7XG5cdFx0XHRcdFx0XHR3aWR0aDogMlxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XSxcblx0ICAgICAgICB2YWx1ZUF4aXM6IHtcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0lJ1xuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgICBsaW5lOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaW46IDAsXG5cdCAgICBcdFx0bWF4OiAxMDBcblx0ICAgICAgICB9LFxuXHQgICAgICAgIGNhdGVnb3J5QXhpczoge1xuXHQgICAgICAgICAgICBtYWpvckdyaWRMaW5lczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWFqb3JUaWNrczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGxhYmVsczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHRcdFx0dG9vbHRpcDoge1xuXHRcdFx0XHRzaGFyZWQ6IHRydWUsXG5cdCAgICAgICAgICAgIHZpc2libGU6IHRydWUsXG5cdFx0XHRcdHNoYXJlZFRlbXBsYXRlOiBnZXRCYXNpY1NoYXJlZFRlbXBsYXRlKCd7MH0lJyksXG5cdFx0XHRcdGJhY2tncm91bmQ6ICcjZTRlNGU0J1xuXHQgICAgICAgIH1cblx0ICAgIH0pLmRhdGEoJ2tlbmRvQ2hhcnQnKTtcblx0fVxuXG5cdGdldCBzeXN0ZW1Db2xvcigpXG5cdHtcblx0XHRyZXR1cm4gJyMzMzk5RkYnO1xuXHR9XG5cblx0Z2V0IHByb2Nlc3NDb2xvcigpXG5cdHtcblx0XHRyZXR1cm4gJyMwMDMzQ0MnO1xuXHR9XG5cblx0YWRkRW50cnkocHJvY2Vzc0xvYWQsIHN5c3RlbUxvYWQpXG5cdHtcblx0XHRsZXQgbmV3RW50cnkgPSB7XG5cdFx0XHR0aW1lOiBnZXRGb3JtYXR0ZWREYXRlVGltZShuZXcgRGF0ZSgpKSxcblx0XHRcdHByb2Nlc3NMb2FkOiBwcm9jZXNzTG9hZCxcblx0XHRcdHN5c3RlbUxvYWQ6IHN5c3RlbUxvYWRcblx0XHR9O1xuXG5cdFx0Ly8gQWRkIGVudHJ5IHRvIGNoYXJ0XG5cdFx0c3VwZXIuX2FkZEVudHJ5KG5ld0VudHJ5KTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NwdS11c2FnZS1jaGFydCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjcHUtdXNhZ2UtY2hhcnQnLCBDcHVVc2FnZUNoYXJ0KTtcbiIsImltcG9ydCB7QmFzZUNoYXJ0fSBmcm9tICcuL2Jhc2UtY2hhcnQnO1xuXG5pbXBvcnQge2dldE1lbW9yeVNoYXJlZFRlbXBsYXRlLCBnZXRNZW1vcnlWYWx1ZUF4aXNMYWJlbFRlbXBsYXRlLCBnZXRGb3JtYXR0ZWREYXRlVGltZX0gZnJvbSAnLi9jaGFydC11dGlscyc7XG5cbmV4cG9ydCBjbGFzcyBNZW1vcnlDaGFydCBleHRlbmRzIEJhc2VDaGFydFxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKDMwMCk7XG5cblx0XHQvLyBBcHBlbmQgdGV4dCB0byBkaXNwbGF5IGVsYXBzZWQgdGltZVxuXHRcdHRoaXMuX2VsYXBzZWRUeHQgPSAkKCc8ZGl2PicsIHtjbGFzczogJ3RleHQtY2VudGVyJywgdGV4dDogJy0tLSd9KTtcblx0XHQkKHRoaXMpLmFwcGVuZCh0aGlzLl9lbGFwc2VkVHh0KTtcblx0fVxuXG5cdF9pbml0Q2hhcnRXaWRnZXQoY2hhcnRIdG1sKVxuXHR7XG5cdFx0cmV0dXJuIGNoYXJ0SHRtbC5rZW5kb0NoYXJ0KHtcblx0XHRcdHRyYW5zaXRpb25zOiBmYWxzZSxcblx0XHRcdGNoYXJ0QXJlYToge1xuXHRcdFx0XHRoZWlnaHQ6IDI0MFxuXHRcdFx0fSxcblx0ICAgICAgICBsZWdlbmQ6IHtcblx0ICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHNlcmllc0RlZmF1bHRzOiB7XG5cdCAgICAgICAgICAgIHR5cGU6ICdhcmVhJyxcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZSxcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG5cdCAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiAndHJhbnNwYXJlbnQnXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXM6IFt7XG5cdFx0XHRcdG5hbWU6ICdBbGxvY2F0ZWQnLFxuXHQgICAgICAgICAgICBmaWVsZDogJ2FsbG9jTWVtJyxcblx0ICAgICAgICAgICAgY2F0ZWdvcnlGaWVsZDogJ3RpbWUnLFxuXHRcdFx0XHRjb2xvcjogdGhpcy5hbGxvY2F0ZWRDb2xvcixcblx0XHRcdFx0bGluZToge1xuXHRcdFx0XHRcdHdpZHRoOiAyXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHRcdFx0e1xuXHRcdFx0XHRuYW1lOiAnVXNlZCcsXG5cdFx0XHRcdGZpZWxkOiAndXNlZE1lbScsXG5cdFx0XHRcdGNhdGVnb3J5RmllbGQ6ICd0aW1lJyxcblx0XHRcdFx0Y29sb3I6IHRoaXMudXNlZENvbG9yLFxuXHRcdFx0XHRsaW5lOiB7XG5cdFx0XHRcdFx0d2lkdGg6IDJcblx0XHRcdFx0fVxuXHRcdFx0fV0sXG5cdCAgICAgICAgdmFsdWVBeGlzOiB7XG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgZm9ybWF0OiAnezB9JyxcbiAgICAgIFx0XHRcdFx0dGVtcGxhdGU6IGdldE1lbW9yeVZhbHVlQXhpc0xhYmVsVGVtcGxhdGUoKVxuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgICBsaW5lOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaW46IDBcblx0ICAgICAgICB9LFxuXHQgICAgICAgIGNhdGVnb3J5QXhpczoge1xuXHRcdFx0XHRtYWpvckdyaWRMaW5lczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWFqb3JUaWNrczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGxhYmVsczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHQgICAgICAgIHRvb2x0aXA6IHtcblx0XHRcdFx0c2hhcmVkOiB0cnVlLFxuXHQgICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHRzaGFyZWRUZW1wbGF0ZTogZ2V0TWVtb3J5U2hhcmVkVGVtcGxhdGUoKSxcblx0XHRcdFx0YmFja2dyb3VuZDogJyNlNGU0ZTQnXG5cdCAgICAgICAgfVxuXHQgICAgfSkuZGF0YSgna2VuZG9DaGFydCcpO1xuXHR9XG5cblx0Z2V0IGFsbG9jYXRlZENvbG9yKClcblx0e1xuXHRcdHJldHVybiAnIzMzOTlGRic7XG5cdH1cblxuXHRnZXQgdXNlZENvbG9yKClcblx0e1xuXHRcdHJldHVybiAnIzAwMzNDQyc7XG5cdH1cblxuXHRhZGRFbnRyeShhbGxvY01lbSwgdXNlZE1lbSlcblx0e1xuXHRcdGxldCBub3cgPSBuZXcgRGF0ZSgpO1xuXG5cdFx0bGV0IG5ld0VudHJ5ID0ge1xuXHRcdFx0dGltZTogZ2V0Rm9ybWF0dGVkRGF0ZVRpbWUobm93KSxcblx0XHRcdHRpbWVzdGFtcDogbm93LmdldFRpbWUoKSxcblx0XHRcdGFsbG9jTWVtOiBhbGxvY01lbSxcblx0XHRcdHVzZWRNZW06IHVzZWRNZW1cblx0XHR9O1xuXG5cdFx0Ly8gQWRkIGVudHJ5IHRvIGNoYXJ0XG5cdFx0c3VwZXIuX2FkZEVudHJ5KG5ld0VudHJ5KTtcblxuXHRcdC8vIFVwZGF0ZSB4IGF4aXNcblx0XHRpZiAoIXRoaXMuaXNQYXVzZWQpXG5cdFx0XHR0aGlzLl91cGRhdGVFbGFwc2VkVGV4dCgpO1xuXHR9XG5cblx0X3VwZGF0ZUVsYXBzZWRUZXh0KClcblx0e1xuXHRcdGxldCBkcyA9IHRoaXMuX2RhdGFTb3VyY2U7XG5cblx0XHRpZiAoZHMudG90YWwoKSA+IDEpXG5cdFx0e1xuXHRcdFx0Ly8gR2V0IGF4aXMgbGltaXRzXG5cdFx0XHRjb25zdCBjaGFydE1pbmltdW0gPSBkcy5hdCgwKS50aW1lc3RhbXA7XG5cdFx0XHRjb25zdCBjaGFydE1heGltdW0gPSBkcy5hdChkcy50b3RhbCgpIC0gMSkudGltZXN0YW1wO1xuXG5cdFx0XHQvLyBTZXQgZWxhcHNlZCB0ZXh0XG5cdFx0XHRsZXQgc2Vjb25kcyA9IE1hdGgucm91bmQoIChjaGFydE1heGltdW0gLSBjaGFydE1pbmltdW0pIC8gMTAwMCApO1xuXHRcdFx0bGV0IHRpdGxlO1xuXG5cdFx0XHRpZiAoc2Vjb25kcyA8IDYwKVxuXHRcdFx0XHR0aXRsZSA9ICdMYXN0ICcgKyAoc2Vjb25kcyAhPSAxID8gc2Vjb25kcyArICcgc2Vjb25kcycgOiAnc2Vjb25kJyk7XG5cdFx0XHRlbHNlXG5cdFx0XHR7XG5cdFx0XHRcdGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKHNlY29uZHMgLyA2MCk7XG5cdFx0XHRcdHRpdGxlID0gJ0xhc3QgJyArIChtaW51dGVzICE9IDEgPyBtaW51dGVzICsgJyBtaW51dGVzJyA6ICdtaW51dGUnKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fZWxhcHNlZFR4dC50ZXh0KHRpdGxlKTtcblx0XHR9XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdtZW1vcnktY2hhcnQnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnbWVtb3J5LWNoYXJ0JywgTWVtb3J5Q2hhcnQpO1xuIiwiaW1wb3J0IHtnZXROZXR3b3JrU2hhcmVkVGVtcGxhdGUsIGdldE5ldHdvcmtWYWx1ZUF4aXNMYWJlbFRlbXBsYXRlfSBmcm9tICcuL2NoYXJ0LXV0aWxzJztcbmltcG9ydCAqIGFzIG1vbWVudCBmcm9tICdtb21lbnQnO1xuXG5leHBvcnQgY2xhc3MgTmV0d29yazI0aENoYXJ0IGV4dGVuZHMgSFRNTEVsZW1lbnRcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdCAgICBzdXBlcigpO1xuXG5cdFx0dGhpcy5fbGFzdFRvdGFsT3V0ID0gMDtcblx0XHR0aGlzLl9sYXN0VG90YWxJbiA9IDA7XG5cdFx0dGhpcy5fbGFzdERhdGUgPSBuZXcgRGF0ZSgpO1xuXHRcdHRoaXMuX3NhbXBsaW5nUmF0ZVNlY29uZHMgPSAwO1xuXG5cdFx0Ly8gQ3JlYXRlIGNoYXJ0IGh0bWxcblx0XHRsZXQgY2hhcnRIdG1sID0gJCgnPGRpdj4nKTtcblx0XHQkKHRoaXMpLmFwcGVuZChjaGFydEh0bWwpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBjaGFydFxuXHRcdHRoaXMuX2NoYXJ0V2lkZ2V0ID0gdGhpcy5faW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbCk7XG5cdH1cblxuXHRfaW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbClcblx0e1xuXHRcdHJldHVybiBjaGFydEh0bWwua2VuZG9DaGFydCh7XG5cdFx0XHR0cmFuc2l0aW9uczogZmFsc2UsXG5cdFx0XHRjaGFydEFyZWE6IHtcblx0XHRcdFx0aGVpZ2h0OiAyNzAsXG5cdFx0XHRcdGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCdcblx0XHRcdH0sXG5cdCAgICAgICAgbGVnZW5kOiB7XG5cdCAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXNEZWZhdWx0czoge1xuXHQgICAgICAgICAgICB0eXBlOiAnYXJlYScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nLFxuXHQgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbe1xuXHRcdFx0XHRuYW1lOiAnT3V0Z29pbmcnLFxuXHQgICAgICAgICAgICBmaWVsZDogJ291dGdvaW5nJyxcblx0ICAgICAgICAgICAgY2F0ZWdvcnlGaWVsZDogJ3RpbWUnLFxuXHRcdFx0XHRjb2xvcjogJyNDQzAwMDAnLFxuXHRcdFx0XHRsaW5lOiB7XG5cdFx0XHRcdFx0d2lkdGg6IDJcblx0XHRcdFx0fVxuXHQgICAgICAgIH0sXG5cdFx0XHR7XG5cdFx0XHRcdG5hbWU6ICdJbmNvbWluZycsXG5cdFx0XHRcdGZpZWxkOiAnaW5jb21pbmcnLFxuXHRcdFx0XHRjYXRlZ29yeUZpZWxkOiAndGltZScsXG5cdFx0XHRcdGNvbG9yOiAnIzAwOTkwMCcsXG5cdFx0XHRcdGxpbmU6IHtcblx0XHRcdFx0XHR3aWR0aDogMlxuXHRcdFx0XHR9XG5cdFx0XHR9XSxcblx0ICAgICAgICB2YWx1ZUF4aXM6IHtcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nLFxuICAgICAgXHRcdFx0XHR0ZW1wbGF0ZTogZ2V0TmV0d29ya1ZhbHVlQXhpc0xhYmVsVGVtcGxhdGUoKVxuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgICBsaW5lOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaW46IDBcblx0ICAgICAgICB9LFxuXHQgICAgICAgIGNhdGVnb3J5QXhpczoge1xuXHRcdFx0XHRtYWpvckdyaWRMaW5lczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogdHJ1ZSxcblx0XHRcdFx0XHRzdGVwOiA2MFxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtYWpvclRpY2tzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogdHJ1ZSxcblx0XHRcdFx0XHRzdGVwOiA2MFxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsYWJlbHM6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHRcdHN0ZXA6IDYwXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGJhc2VVbml0OiAnbWludXRlcycsXG5cdFx0XHRcdHR5cGU6ICdkYXRlJyxcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHRvb2x0aXA6IHtcblx0XHRcdFx0c2hhcmVkOiB0cnVlLFxuXHQgICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHRzaGFyZWRUZW1wbGF0ZTogZ2V0TmV0d29ya1NoYXJlZFRlbXBsYXRlKCdkZCBNTU0gSEg6bW0nKSxcblx0XHRcdFx0YmFja2dyb3VuZDogJyNlNGU0ZTQnXG5cdCAgICAgICAgfVxuXHQgICAgfSkuZGF0YSgna2VuZG9DaGFydCcpO1xuXHR9XG5cblx0cmVkcmF3KClcblx0e1xuXHRcdHRoaXMuX2NoYXJ0V2lkZ2V0LnJlZHJhdygpO1xuXHR9XG5cblx0c2V0IHJhbmdlKHZhbHVlcylcblx0e1xuXHRcdHRoaXMuX3JhbmdlID0gdmFsdWVzO1xuXG5cdFx0dGhpcy5fdXBkYXRlWEF4aXNMaW1pdHMoKTtcblx0fVxuXG5cdGdldCByYW5nZSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fcmFuZ2U7XG5cdH1cblxuXHRhZGRIaXN0b3J5RW50cmllcyhvdXRnb2luZ0RhdGEsIGluY29taW5nRGF0YSwgc2FtcGxpbmdSYXRlU2Vjb25kcywgc2hpZnRTZWNvbmRzKVxuXHR7XG5cdFx0dGhpcy5fc2FtcGxpbmdSYXRlU2Vjb25kcyA9IHNhbXBsaW5nUmF0ZVNlY29uZHM7XG5cblx0XHRsZXQgbm93ID0gbmV3IERhdGUoKTtcblxuXHRcdC8vIE5PVEU6IG91dGdvaW5nRGF0YSBhbmQgaW5jb21pbkRhdGEgYXJlIHN1cHBvc2VkIHRvIGhhdmUgdGhlIHNhbWUgc2l6ZSEhIVxuXG5cdFx0aWYgKG91dGdvaW5nRGF0YS5sZW5ndGggPiAwKVxuXHRcdHtcblx0XHRcdGxldCBzdGFydCA9IG1vbWVudChub3cpO1xuXHRcdFx0c3RhcnQuc3VidHJhY3QoKHNhbXBsaW5nUmF0ZVNlY29uZHMgKiBvdXRnb2luZ0RhdGEubGVuZ3RoKSArIHNoaWZ0U2Vjb25kcywgJ3MnKVxuXG5cdFx0XHR0aGlzLl9sYXN0VG90YWxPdXQgPSBvdXRnb2luZ0RhdGFbMF07XG5cdFx0XHR0aGlzLl9sYXN0VG90YWxJbiA9IGluY29taW5nRGF0YVswXTtcblx0XHRcdHRoaXMuX2xhc3REYXRlID0gc3RhcnQudG9EYXRlKCk7XG5cblx0XHRcdGlmIChvdXRnb2luZ0RhdGEubGVuZ3RoID4gMSlcblx0XHRcdHtcblx0XHRcdFx0bGV0IGRhdGFTb3VyY2UgPSBuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKCk7XG5cblx0XHRcdFx0Zm9yIChsZXQgaSA9IDE7IGkgPCBvdXRnb2luZ0RhdGEubGVuZ3RoOyBpKyspXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRjb25zdCB0b3RhbE91dCA9IG91dGdvaW5nRGF0YVtpXTtcblx0XHRcdFx0XHRjb25zdCB0b3RhbEluID0gaW5jb21pbmdEYXRhW2ldO1xuXG5cdFx0XHRcdFx0bGV0IGRhdGUgPSBzdGFydC5jbG9uZSgpO1xuXHRcdFx0XHRcdGRhdGUuYWRkKGkgKiBzYW1wbGluZ1JhdGVTZWNvbmRzLCAncycpO1xuXG5cdFx0XHRcdFx0dGhpcy5hZGRFbnRyeSh0b3RhbE91dCwgdG90YWxJbiwgZGF0YVNvdXJjZSwgZGF0ZS50b0RhdGUoKSwgZmFsc2UpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQXNzaWduIGRhdGFzb3VyY2UgdG8gY2hhcnRcblx0XHRcdFx0dGhpcy5fY2hhcnRXaWRnZXQuc2V0RGF0YVNvdXJjZShkYXRhU291cmNlKTtcblxuXHRcdFx0XHQvLyBVcGRhdGUgYXhpc1xuXHRcdFx0XHR0aGlzLl91cGRhdGVYQXhpc0xpbWl0cygpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0dGhpcy5fbGFzdFRvdGFsT3V0ID0gMDtcblx0XHRcdHRoaXMuX2xhc3RUb3RhbEluID0gMDtcblx0XHRcdHRoaXMuX2xhc3REYXRlID0gbm93O1xuXHRcdH1cblx0fVxuXG5cdGFkZEVudHJ5KHRvdGFsT3V0LCB0b3RhbEluLCBkYXRhU291cmNlID0gbnVsbCwgZGF0ZSA9IG51bGwsIHVwZGF0ZUF4aXMgPSB0cnVlKVxuXHR7XG5cdFx0aWYgKGRhdGUgPT0gbnVsbClcblx0XHRcdGRhdGUgPSBuZXcgRGF0ZSgpO1xuXG5cdFx0Y29uc3QgZWxhcHNlZFNlY3MgPSBNYXRoLnJvdW5kKChkYXRlLmdldFRpbWUoKSAtIHRoaXMuX2xhc3REYXRlLmdldFRpbWUoKSkgLyAxMDAwKTtcblxuXHRcdC8vIFRoZSAyNGggY2hhcnQgaXMgdXBkYXRlZCBhdCB0aGUgc2FtZSBzYW1wbGluZyByYXRlIHVzZWQgYnkgdGhlIHNlcnZlciB0byBzYXZlIHRoZSB0cmFmZmljIGhpc3Rvcnlcblx0XHRpZiAoZWxhcHNlZFNlY3MgPj0gdGhpcy5fc2FtcGxpbmdSYXRlU2Vjb25kcylcblx0XHR7XG5cdFx0XHRsZXQgbmV3RW50cnkgPSB7XG5cdFx0XHRcdHRpbWU6IGRhdGUsXG5cdFx0XHRcdG91dGdvaW5nOiBNYXRoLnJvdW5kKCh0b3RhbE91dCAtIHRoaXMuX2xhc3RUb3RhbE91dCkgLyBlbGFwc2VkU2VjcyksXG5cdFx0XHRcdGluY29taW5nOiBNYXRoLnJvdW5kKCh0b3RhbEluIC0gdGhpcy5fbGFzdFRvdGFsSW4pIC8gZWxhcHNlZFNlY3MpXG5cdFx0XHR9O1xuXG5cdFx0XHQvLyBBZGQgZW50cnkgdG8gZGF0YSBzb3VyY2Vcblx0XHRcdGlmIChkYXRhU291cmNlID09IG51bGwpXG5cdFx0XHRcdGRhdGFTb3VyY2UgPSB0aGlzLl9kYXRhU291cmNlO1xuXG5cdFx0XHRkYXRhU291cmNlLmFkZChuZXdFbnRyeSk7XG5cblx0XHRcdHRoaXMuX2xhc3RUb3RhbE91dCA9IHRvdGFsT3V0O1xuXHRcdFx0dGhpcy5fbGFzdFRvdGFsSW4gPSB0b3RhbEluO1xuXHRcdFx0dGhpcy5fbGFzdERhdGUgPSBkYXRlO1xuXG5cdFx0XHRpZiAodXBkYXRlQXhpcylcblx0XHRcdFx0dGhpcy5fdXBkYXRlWEF4aXNMaW1pdHMoKTtcblx0XHR9XG5cdH1cblxuXHRfdXBkYXRlWEF4aXNMaW1pdHMoKVxuXHR7XG5cdFx0bGV0IGRzID0gdGhpcy5fZGF0YVNvdXJjZTtcblxuXHRcdGlmIChkcy50b3RhbCgpID4gMClcblx0XHR7XG5cdFx0XHRjb25zdCBjaGFydE1pbmltdW0gPSBtb21lbnQodGhpcy5fbGFzdERhdGUpLmFkZCh0aGlzLl9yYW5nZVswXSwgJ2gnKTtcblx0XHRcdGNvbnN0IGNoYXJ0TWF4aW11bSA9IG1vbWVudCh0aGlzLl9sYXN0RGF0ZSkuYWRkKHRoaXMuX3JhbmdlWzFdLCAnaCcpO1xuXG5cdFx0XHR0aGlzLl9jaGFydFdpZGdldC5vcHRpb25zLmNhdGVnb3J5QXhpcy5taW4gPSBjaGFydE1pbmltdW0udG9EYXRlKCk7XG5cdFx0XHR0aGlzLl9jaGFydFdpZGdldC5vcHRpb25zLmNhdGVnb3J5QXhpcy5tYXggPSBjaGFydE1heGltdW0udG9EYXRlKCk7XG5cblx0XHRcdHRoaXMuX2NoYXJ0V2lkZ2V0LnJlZHJhdygpO1xuXHRcdH1cblx0fVxuXG5cdGdldCBfZGF0YVNvdXJjZSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fY2hhcnRXaWRnZXQuZGF0YVNvdXJjZTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ25ldHdvcmstMjRoLWNoYXJ0JykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ25ldHdvcmstMjRoLWNoYXJ0JywgTmV0d29yazI0aENoYXJ0KTtcbiIsImltcG9ydCB7QmFzZUNoYXJ0fSBmcm9tICcuL2Jhc2UtY2hhcnQnO1xuXG5pbXBvcnQge2dldE5ldHdvcmtTaGFyZWRUZW1wbGF0ZSwgZ2V0TmV0d29ya1ZhbHVlQXhpc0xhYmVsVGVtcGxhdGUsIGdldEZvcm1hdHRlZERhdGVUaW1lfSBmcm9tICcuL2NoYXJ0LXV0aWxzJztcblxuZXhwb3J0IGNsYXNzIE5ldHdvcmtSZWFsdGltZUNoYXJ0IGV4dGVuZHMgQmFzZUNoYXJ0XG57XG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHQgICAgc3VwZXIoMzAwKTtcblxuXHRcdHRoaXMuX2xhc3RUb3RhbEtiT3V0ID0gMDtcblx0XHR0aGlzLl9sYXN0VG90YWxLYkluID0gMDtcblx0XHR0aGlzLl9sYXN0VGltZSA9IDA7XG5cblx0XHQvLyBBcHBlbmQgdGV4dCB0byBkaXNwbGF5IGVsYXBzZWQgdGltZVxuXHRcdHRoaXMuX2VsYXBzZWRUeHQgPSAkKCc8ZGl2PicsIHtjbGFzczogJ3RleHQtY2VudGVyJywgdGV4dDogJy0tLSd9KTtcblx0XHQkKHRoaXMpLmFwcGVuZCh0aGlzLl9lbGFwc2VkVHh0KTtcblx0fVxuXG5cdF9pbml0Q2hhcnRXaWRnZXQoY2hhcnRIdG1sKVxuXHR7XG5cdFx0cmV0dXJuIGNoYXJ0SHRtbC5rZW5kb0NoYXJ0KHtcblx0XHRcdHRyYW5zaXRpb25zOiBmYWxzZSxcblx0XHRcdGNoYXJ0QXJlYToge1xuXHRcdFx0XHRoZWlnaHQ6IDI3MCxcblx0XHRcdFx0YmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHRcdFx0fSxcblx0ICAgICAgICBsZWdlbmQ6IHtcblx0ICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHNlcmllc0RlZmF1bHRzOiB7XG5cdCAgICAgICAgICAgIHR5cGU6ICdhcmVhJyxcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZSxcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG5cdCAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiAndHJhbnNwYXJlbnQnXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXM6IFt7XG5cdFx0XHRcdG5hbWU6ICdPdXRnb2luZycsXG5cdCAgICAgICAgICAgIGZpZWxkOiAnb3V0Z29pbmcnLFxuXHQgICAgICAgICAgICBjYXRlZ29yeUZpZWxkOiAndGltZScsXG5cdFx0XHRcdGNvbG9yOiB0aGlzLm91dGdvaW5nQ29sb3IsXG5cdFx0XHRcdGxpbmU6IHtcblx0XHRcdFx0XHR3aWR0aDogMlxuXHRcdFx0XHR9XG5cdCAgICAgICAgfSxcblx0XHRcdHtcblx0XHRcdFx0bmFtZTogJ0luY29taW5nJyxcblx0XHRcdFx0ZmllbGQ6ICdpbmNvbWluZycsXG5cdFx0XHRcdGNhdGVnb3J5RmllbGQ6ICd0aW1lJyxcblx0XHRcdFx0Y29sb3I6IHRoaXMuaW5jb21pbmdDb2xvcixcblx0XHRcdFx0bGluZToge1xuXHRcdFx0XHRcdHdpZHRoOiAyXG5cdFx0XHRcdH1cblx0XHRcdH1dLFxuXHQgICAgICAgIHZhbHVlQXhpczoge1xuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG4gICAgICBcdFx0XHRcdHRlbXBsYXRlOiBnZXROZXR3b3JrVmFsdWVBeGlzTGFiZWxUZW1wbGF0ZSgpXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICAgIGxpbmU6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1pbjogMCxcblx0ICAgICAgICB9LFxuXHQgICAgICAgIGNhdGVnb3J5QXhpczoge1xuXHRcdFx0XHRtYWpvckdyaWRMaW5lczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWFqb3JUaWNrczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGxhYmVsczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHQgICAgICAgIHRvb2x0aXA6IHtcblx0XHRcdFx0c2hhcmVkOiB0cnVlLFxuXHQgICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHRzaGFyZWRUZW1wbGF0ZTogZ2V0TmV0d29ya1NoYXJlZFRlbXBsYXRlKCksXG5cdFx0XHRcdGJhY2tncm91bmQ6ICcjZTRlNGU0J1xuXHQgICAgICAgIH1cblx0ICAgIH0pLmRhdGEoJ2tlbmRvQ2hhcnQnKTtcblx0fVxuXG5cdGdldCBvdXRnb2luZ0NvbG9yKClcblx0e1xuXHRcdHJldHVybiAnI0NDMDAwMCc7XG5cdH1cblxuXHRnZXQgaW5jb21pbmdDb2xvcigpXG5cdHtcblx0XHRyZXR1cm4gJyMwMDk5MDAnO1xuXHR9XG5cblx0YWRkRW50cnkodG90YWxPdXRLYiwgdG90YWxJbktiKVxuXHR7XG5cdFx0bGV0IG5vdyA9IG5ldyBEYXRlKClcblx0XHRsZXQgdGltZSA9IG5vdy5nZXRUaW1lKCk7XG5cblx0XHQvLyBUaGUgZmlyc3QgdmFsdWUgc2VudCBieSB0aGUgc2VydmVyIGlzIG5vdCBwbG90dGVkOiBpdCB3b3VsZCBiZSBhIHdvcm5nIHZhbHVlIGJlY2F1c2Vcblx0XHQvLyB3ZSBoYXZlIHRvIGNhbGN1bGF0ZSBpdCBhcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHR3byB0b3RhbCB2YWx1ZXMsIGJ1dCB3ZSBkb24ndCBoYXZlIHRoZSBwcmV2aW91cyBvbmVcblx0XHRpZiAodGhpcy5fbGFzdFRpbWUgPiAwKVxuXHRcdHtcblx0XHRcdGxldCBlbGFwc2VkU2VjcyA9ICh0aW1lIC0gdGhpcy5fbGFzdFRpbWUpIC8gMTAwMDtcblxuXHRcdFx0Y29uc3QgdmFsdWVPdXQgPSBNYXRoLnJvdW5kKCh0b3RhbE91dEtiIC0gdGhpcy5fbGFzdFRvdGFsS2JPdXQpIC8gZWxhcHNlZFNlY3MpO1xuXHRcdFx0Y29uc3QgdmFsdWVJbiA9IE1hdGgucm91bmQoKHRvdGFsSW5LYiAtIHRoaXMuX2xhc3RUb3RhbEtiSW4pIC8gZWxhcHNlZFNlY3MpO1xuXG5cdFx0XHRsZXQgbmV3RW50cnkgPSB7XG5cdFx0XHRcdHRpbWU6IGdldEZvcm1hdHRlZERhdGVUaW1lKG5vdyksXG5cdFx0XHRcdHRpbWVzdGFtcDogdGltZSxcblx0XHRcdFx0b3V0Z29pbmc6IHZhbHVlT3V0LFxuXHRcdFx0XHRpbmNvbWluZzogdmFsdWVJblxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gQWRkIGVudHJ5IHRvIGNoYXJ0XG5cdFx0XHRzdXBlci5fYWRkRW50cnkobmV3RW50cnkpO1xuXG5cdFx0XHQvLyBVcGRhdGUgeCBheGlzXG5cdFx0XHRpZiAoIXRoaXMuaXNQYXVzZWQpXG5cdFx0XHRcdHRoaXMuX3VwZGF0ZUVsYXBzZWRUZXh0KCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fbGFzdFRvdGFsS2JPdXQgPSB0b3RhbE91dEtiO1xuXHRcdHRoaXMuX2xhc3RUb3RhbEtiSW4gPSB0b3RhbEluS2I7XG5cdFx0dGhpcy5fbGFzdFRpbWUgPSB0aW1lO1xuXHR9XG5cblx0X3VwZGF0ZUVsYXBzZWRUZXh0KClcblx0e1xuXHRcdGxldCBkcyA9IHRoaXMuX2RhdGFTb3VyY2U7XG5cblx0XHRpZiAoZHMudG90YWwoKSA+IDEpXG5cdFx0e1xuXHRcdFx0Ly8gR2V0IGF4aXMgbGltaXRzXG5cdFx0XHRjb25zdCBjaGFydE1pbmltdW0gPSBkcy5hdCgwKS50aW1lc3RhbXA7XG5cdFx0XHRjb25zdCBjaGFydE1heGltdW0gPSBkcy5hdChkcy50b3RhbCgpIC0gMSkudGltZXN0YW1wO1xuXG5cdFx0XHQvLyBTZXQgZWxhcHNlZCB0ZXh0XG5cdFx0XHRsZXQgdGl0bGU7XG5cdFx0XHRsZXQgc2Vjb25kcyA9IE1hdGgucm91bmQoIChjaGFydE1heGltdW0gLSBjaGFydE1pbmltdW0pIC8gMTAwMCApO1xuXG5cdFx0XHRpZiAoc2Vjb25kcyA8IDYwKVxuXHRcdFx0XHR0aXRsZSA9ICdMYXN0ICcgKyAoc2Vjb25kcyAhPSAxID8gc2Vjb25kcyArICcgc2Vjb25kcycgOiAnc2Vjb25kJyk7XG5cdFx0XHRlbHNlXG5cdFx0XHR7XG5cdFx0XHRcdGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKHNlY29uZHMgLyA2MCk7XG5cdFx0XHRcdHRpdGxlID0gJ0xhc3QgJyArIChtaW51dGVzICE9IDEgPyBtaW51dGVzICsgJyBtaW51dGVzJyA6ICdtaW51dGUnKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fZWxhcHNlZFR4dC50ZXh0KHRpdGxlKTtcblx0XHR9XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCduZXR3b3JrLXJlYWx0aW1lLWNoYXJ0JykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ25ldHdvcmstcmVhbHRpbWUtY2hhcnQnLCBOZXR3b3JrUmVhbHRpbWVDaGFydCk7XG4iLCJpbXBvcnQge0Jhc2VDaGFydH0gZnJvbSAnLi9iYXNlLWNoYXJ0JztcblxuaW1wb3J0IHtnZXRCYXNpY1NoYXJlZFRlbXBsYXRlLCBnZXRGb3JtYXR0ZWREYXRlVGltZX0gZnJvbSAnLi9jaGFydC11dGlscyc7XG5cbmV4cG9ydCBjbGFzcyBTeXN0ZW1RdWV1ZUNoYXJ0IGV4dGVuZHMgQmFzZUNoYXJ0XG57XG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHQgICAgc3VwZXIoMjQwKTtcblxuXHRcdHRoaXMuX2F2ZXJhZ2VMb2FkID0gMDtcblx0fVxuXG5cdF9pbml0aWFsaXplKClcblx0e1xuXHRcdGNvbnN0IGNoYXJ0SGVpZ2h0ID0gMjQwO1xuXG5cdFx0Ly8gQXBwZW5kIGNvbnRhaW5lciBmb3IgY2hhcnQgJiBnYXVnZVxuXHRcdGxldCBjb250YWluZXIgPSAkKCc8ZGl2PicsIHtjbGFzczogJ2QtZmxleCBmbGV4LXJvdyd9KTtcblx0XHQkKHRoaXMpLmFwcGVuZChjb250YWluZXIpO1xuXG5cdFx0Ly8gQ0hBUlRcblxuXHRcdGxldCBjaGFydENvbnRhaW5lciA9ICQoJzxkaXY+Jywge2NsYXNzOiAnZmxleC1ncm93LTEnfSk7XG5cdFx0Y29udGFpbmVyLmFwcGVuZChjaGFydENvbnRhaW5lcik7XG5cblx0XHQvLyBDcmVhdGUgY2hhcnQgaHRtbFxuXHRcdGxldCBjaGFydEh0bWwgPSAkKCc8ZGl2PicpO1xuXHRcdGNoYXJ0Q29udGFpbmVyLmFwcGVuZChjaGFydEh0bWwpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBjaGFydFxuXHRcdHRoaXMuX2NoYXJ0V2lkZ2V0ID0gdGhpcy5faW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbCwgY2hhcnRIZWlnaHQpO1xuXG5cdFx0Ly8gQXBwZW5kIHRleHQgdG8gZGlzcGxheSBlbGFwc2VkIHRpbWVcblx0XHR0aGlzLl9lbGFwc2VkVHh0ID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICd0ZXh0LWNlbnRlcicsIHRleHQ6ICctLS0nfSk7XG5cdFx0Y2hhcnRDb250YWluZXIuYXBwZW5kKHRoaXMuX2VsYXBzZWRUeHQpO1xuXG5cdFx0Ly8gR0FVR0VcblxuXHRcdGxldCBnYXVnZUNvbnRhaW5lciA9ICQoJzxkaXY+Jyk7XG5cdFx0Y29udGFpbmVyLmFwcGVuZChnYXVnZUNvbnRhaW5lcik7XG5cblx0XHQvLyBDcmVhdGUgZ2F1Z2UgaHRtbFxuXHRcdGxldCBnYXVnZUh0bWwgPSAkKCc8ZGl2PicpO1xuXHRcdGdhdWdlQ29udGFpbmVyLmFwcGVuZChnYXVnZUh0bWwpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBnYXVnZVxuXHRcdHRoaXMuX2dhdWdlV2lkZ2V0ID0gdGhpcy5faW5pdEdhdWdlV2lkZ2V0KGdhdWdlSHRtbCwgY2hhcnRIZWlnaHQpO1xuXG5cdFx0Ly8gQXBwZW5kIHRleHQgdG8gZGlzcGxheSBsb2FkXG5cdFx0dGhpcy5fbG9hZFR4dCA9ICQoJzxkaXY+Jywge2NsYXNzOiAndGV4dC1jZW50ZXIgZm9udC13ZWlnaHQtYm9sZCcsIHRleHQ6ICctLS0nfSk7XG5cdFx0Z2F1Z2VDb250YWluZXIuYXBwZW5kKHRoaXMuX2xvYWRUeHQpO1xuXG5cdFx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRcdC8vIFJlc2V0IGRhdGEgc291cmNlXG5cdFx0dGhpcy5yZXNldCgpO1xuXHR9XG5cblx0X2luaXRDaGFydFdpZGdldChjaGFydEh0bWwsIGhlaWdodClcblx0e1xuXHRcdHJldHVybiBjaGFydEh0bWwua2VuZG9DaGFydCh7XG5cdFx0XHR0cmFuc2l0aW9uczogZmFsc2UsXG5cdFx0XHRjaGFydEFyZWE6IHtcblx0XHRcdFx0aGVpZ2h0OiBoZWlnaHQsXG5cdFx0XHRcdGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCdcblx0XHRcdH0sXG5cdCAgICAgICAgbGVnZW5kOiB7XG5cdCAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXNEZWZhdWx0czoge1xuXHQgICAgICAgICAgICB0eXBlOiAnYXJlYScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nLFxuXHQgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXM6IFtcblx0XHRcdFx0e1xuXHRcdFx0XHRcdG5hbWU6ICdNZXNzYWdlcycsXG5cdFx0ICAgICAgICAgICAgZmllbGQ6ICdsb2FkJyxcblx0XHQgICAgICAgICAgICBjYXRlZ29yeUZpZWxkOiAndGltZScsXG5cdFx0XHRcdFx0Y29sb3I6ICcjMzM5OWZmJyxcblx0XHRcdFx0XHRsaW5lOiB7XG5cdFx0XHRcdFx0XHR3aWR0aDogMlxuXHRcdFx0XHRcdH1cblx0XHQgICAgICAgIH1cblx0XHRcdF0sXG5cdCAgICAgICAgdmFsdWVBeGlzOiB7XG5cdFx0XHRcdHRpdGxlOiB7XG5cdFx0XHRcdFx0dGV4dDogJ01lc3NhZ2VzJ1xuXHRcdFx0XHR9LFxuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfSdcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICAgICAgbGluZToge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWluOiAwXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBjYXRlZ29yeUF4aXM6IHtcblx0ICAgICAgICAgICAgbWFqb3JHcmlkTGluZXM6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1ham9yVGlja3M6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiBmYWxzZVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsYWJlbHM6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiBmYWxzZVxuXHRcdFx0XHR9XG5cdCAgICAgICAgfSxcblx0XHRcdHRvb2x0aXA6IHtcblx0XHRcdFx0c2hhcmVkOiB0cnVlLFxuXHQgICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHRzaGFyZWRUZW1wbGF0ZTogZ2V0QmFzaWNTaGFyZWRUZW1wbGF0ZSgpLFxuXHRcdFx0XHRiYWNrZ3JvdW5kOiAnI2U0ZTRlNCdcblx0ICAgICAgICB9XG5cdCAgICB9KS5kYXRhKCdrZW5kb0NoYXJ0Jyk7XG5cdH1cblxuXHRfaW5pdEdhdWdlV2lkZ2V0KGdhdWdlSHRtbCwgaGVpZ2h0KVxuXHR7XG5cdFx0cmV0dXJuIGdhdWdlSHRtbC5rZW5kb0xpbmVhckdhdWdlKHtcblx0XHRcdHBvaW50ZXI6IHtcblx0ICAgICAgICAgICAgdmFsdWU6IDAsXG5cdCAgICAgICAgICAgIHNoYXBlOiAnYXJyb3cnLFxuXHQgICAgICAgICAgXHRzaXplOiAxMCxcblx0XHRcdFx0Y29sb3I6ICcjMjEyNTI5J1xuXHQgICAgICAgIH0sXG5cdFx0XHRnYXVnZUFyZWE6IHtcblx0XHRcdFx0aGVpZ2h0OiBoZWlnaHRcblx0XHRcdH0sXG5cdCAgICAgICAgc2NhbGU6IHtcblx0ICAgICAgICAgICAgbWFqb3JVbml0OiAxMCxcblx0ICAgICAgICAgICAgbWlub3JVbml0OiAxLFxuXHRcdFx0XHRtaW46IDAsXG5cdFx0XHRcdG1heDogMTAwLFxuXHQgICAgICAgICAgICByYW5nZXM6IFtcblx0ICAgICAgICAgICAgICAgIHtcblx0XHRcdFx0XHRcdGZyb206IDAsXG5cdCAgICAgICAgICAgICAgICAgICAgdG86IDUwLFxuXHQgICAgICAgICAgICAgICAgICAgIGNvbG9yOiAnIzAwY2MwMCcsXG5cdCAgICAgICAgICAgICAgICAgIFx0b3BhY2l0eTogLjVcblx0ICAgICAgICAgICAgICAgIH0sIHtcblx0ICAgICAgICAgICAgICAgICAgICBmcm9tOiA1MCxcblx0ICAgICAgICAgICAgICAgICAgICB0bzogNzUsXG5cdCAgICAgICAgICAgICAgICAgICAgY29sb3I6ICcjZmZlMTA2Jyxcblx0ICAgICAgICAgICAgICAgICAgXHRvcGFjaXR5OiAuNVxuXHQgICAgICAgICAgICAgICAgfSwge1xuXHQgICAgICAgICAgICAgICAgICAgIGZyb206IDc1LFxuXHQgICAgICAgICAgICAgICAgICAgIHRvOiAxMDAsXG5cdCAgICAgICAgICAgICAgICAgICAgY29sb3I6ICcjZWQxNjAxJyxcblx0ICAgICAgICAgICAgICAgICAgXHRvcGFjaXR5OiAuNVxuXHQgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICBdLFxuXHQgICAgICAgICAgXHRtYWpvclRpY2tzOiB7XG5cdCAgICAgICAgICAgICAgdmlzaWJsZTogdHJ1ZSxcblx0ICAgICAgICAgICAgICBzaXplOiAxMFxuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgXHRtaW5vclRpY2tzOiB7XG5cdCAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICAgIFx0bGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICAgIFx0bGluZToge1xuXHQgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICBcdHJhbmdlU2l6ZTogMTBcblx0ICAgICAgICB9XG5cdCAgICB9KS5kYXRhKCdrZW5kb0xpbmVhckdhdWdlJyk7XG5cdH1cblxuXHRhZGRFbnRyeShsb2FkLCBxdWV1ZU1zZ0xpbWl0KVxuXHR7XG5cdFx0Ly8gQ0hBUlRcblxuXHRcdGxldCBub3cgPSBuZXcgRGF0ZSgpO1xuXG5cdFx0bGV0IG5ld0VudHJ5ID0ge1xuXHRcdFx0dGltZTogZ2V0Rm9ybWF0dGVkRGF0ZVRpbWUobm93KSxcblx0XHRcdHRpbWVzdGFtcDogbm93LmdldFRpbWUoKSxcblx0XHRcdGxvYWQ6IGxvYWRcblx0XHR9O1xuXG5cdFx0Ly8gQWRkIGVudHJ5IHRvIGNoYXJ0XG5cdFx0c3VwZXIuX2FkZEVudHJ5KG5ld0VudHJ5KTtcblxuXHRcdC8vIFVwZGF0ZSB4IGF4aXNcblx0XHRpZiAoIXRoaXMuaXNQYXVzZWQpXG5cdFx0XHR0aGlzLl91cGRhdGVFbGFwc2VkVGV4dCgpO1xuXG5cdFx0Ly8gR0FVR0VcblxuXHRcdC8vIEV2YWx1YXRlIGF2ZXJhZ2Vcblx0XHRsZXQgbnVtVmFsdWVzID0gdGhpcy5fZGF0YVNvdXJjZS50b3RhbCgpO1xuXG5cdFx0aWYgKG51bVZhbHVlcyA+IDApXG5cdFx0e1xuXHRcdFx0bGV0IHRvdGFsID0gMDtcblx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgbnVtVmFsdWVzOyBpKyspXG5cdFx0XHRcdHRvdGFsICs9IHRoaXMuX2RhdGFTb3VyY2UuYXQoaSkubG9hZDtcblxuXHRcdFx0dGhpcy5fYXZlcmFnZUxvYWQgPSBNYXRoLnJvdW5kKHRvdGFsIC8gbnVtVmFsdWVzKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fYXZlcmFnZUxvYWQgPSAwO1xuXG5cdFx0Y29uc3QgYXZnTG9hZFBlcmMgPSBNYXRoLnJvdW5kKHRoaXMuX2F2ZXJhZ2VMb2FkIC8gcXVldWVNc2dMaW1pdCAqIDEwMDApIC8gMTA7XG5cblx0XHQvLyBTZXQgZ2F1Z2UgdmFsdWVcblx0XHR0aGlzLl9nYXVnZVdpZGdldC52YWx1ZShhdmdMb2FkUGVyYyk7XG5cblx0XHQvLyBTZXQgbG9hZCB0ZXh0XG5cdFx0dGhpcy5fbG9hZFR4dC50ZXh0KGF2Z0xvYWRQZXJjICsgJyUnKVxuXHR9XG5cblx0X3VwZGF0ZUVsYXBzZWRUZXh0KClcblx0e1xuXHRcdGxldCBkcyA9IHRoaXMuX2RhdGFTb3VyY2U7XG5cblx0XHRpZiAoZHMudG90YWwoKSA+IDEpXG5cdFx0e1xuXHRcdFx0Ly8gR2V0IGF4aXMgbGltaXRzXG5cdFx0XHRjb25zdCBjaGFydE1pbmltdW0gPSBkcy5hdCgwKS50aW1lc3RhbXA7XG5cdFx0XHRjb25zdCBjaGFydE1heGltdW0gPSBkcy5hdChkcy50b3RhbCgpIC0gMSkudGltZXN0YW1wO1xuXG5cdFx0XHQvLyBTZXQgZWxhcHNlZCB0ZXh0XG5cdFx0XHRsZXQgc2Vjb25kcyA9IE1hdGgucm91bmQoIChjaGFydE1heGltdW0gLSBjaGFydE1pbmltdW0pIC8gMTAwMCApO1xuXHRcdFx0bGV0IHRpdGxlO1xuXG5cdFx0XHRpZiAoc2Vjb25kcyA8IDYwKVxuXHRcdFx0XHR0aXRsZSA9ICdMYXN0ICcgKyAoc2Vjb25kcyAhPSAxID8gc2Vjb25kcyArICcgc2Vjb25kcycgOiAnc2Vjb25kJyk7XG5cdFx0XHRlbHNlXG5cdFx0XHR7XG5cdFx0XHRcdGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKHNlY29uZHMgLyA2MCk7XG5cdFx0XHRcdHRpdGxlID0gJ0xhc3QgJyArIChtaW51dGVzICE9IDEgPyBtaW51dGVzICsgJyBtaW51dGVzJyA6ICdtaW51dGUnKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fZWxhcHNlZFR4dC50ZXh0KHRpdGxlKTtcblx0XHR9XG5cdH1cblxuXHRnZXQgbG9hZCgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fYXZlcmFnZUxvYWQ7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdzeXN0ZW0tcXVldWUtY2hhcnQnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnc3lzdGVtLXF1ZXVlLWNoYXJ0JywgU3lzdGVtUXVldWVDaGFydCk7XG4iLCJpbXBvcnQge0Jhc2VDaGFydH0gZnJvbSAnLi9iYXNlLWNoYXJ0JztcblxuaW1wb3J0IHtnZXRCYXNpY1NoYXJlZFRlbXBsYXRlLCBnZXRGb3JtYXR0ZWREYXRlVGltZX0gZnJvbSAnLi9jaGFydC11dGlscyc7XG5cbmV4cG9ydCBjbGFzcyBTeXN0ZW1Xb3JrbG9hZENoYXJ0IGV4dGVuZHMgQmFzZUNoYXJ0XG57XG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHQgICAgc3VwZXIoMjQwKTtcblx0fVxuXG5cdF9pbml0aWFsaXplKClcblx0e1xuXHRcdGNvbnN0IGNoYXJ0SGVpZ2h0ID0gMjQwO1xuXG5cdFx0Ly8gQXBwZW5kIGNvbnRhaW5lciBmb3IgY2hhcnQgJiBnYXVnZVxuXHRcdGxldCBjb250YWluZXIgPSAkKCc8ZGl2PicsIHtjbGFzczogJ2QtZmxleCBmbGV4LXJvdyd9KTtcblx0XHQkKHRoaXMpLmFwcGVuZChjb250YWluZXIpO1xuXG5cdFx0Ly8gQ0hBUlRcblxuXHRcdGxldCBjaGFydENvbnRhaW5lciA9ICQoJzxkaXY+Jywge2NsYXNzOiAnZmxleC1ncm93LTEnfSk7XG5cdFx0Y29udGFpbmVyLmFwcGVuZChjaGFydENvbnRhaW5lcik7XG5cblx0XHQvLyBDcmVhdGUgY2hhcnQgaHRtbFxuXHRcdGxldCBjaGFydEh0bWwgPSAkKCc8ZGl2PicpO1xuXHRcdGNoYXJ0Q29udGFpbmVyLmFwcGVuZChjaGFydEh0bWwpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBjaGFydFxuXHRcdHRoaXMuX2NoYXJ0V2lkZ2V0ID0gdGhpcy5faW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbCwgY2hhcnRIZWlnaHQpO1xuXG5cdFx0Ly8gQXBwZW5kIHRleHQgdG8gZGlzcGxheSBlbGFwc2VkIHRpbWVcblx0XHR0aGlzLl9lbGFwc2VkVHh0ID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICd0ZXh0LWNlbnRlcicsIHRleHQ6ICctLS0nfSk7XG5cdFx0Y2hhcnRDb250YWluZXIuYXBwZW5kKHRoaXMuX2VsYXBzZWRUeHQpO1xuXG5cdFx0Ly8gR0FVR0VcblxuXHRcdGxldCBnYXVnZUNvbnRhaW5lciA9ICQoJzxkaXY+Jyk7XG5cdFx0Y29udGFpbmVyLmFwcGVuZChnYXVnZUNvbnRhaW5lcik7XG5cblx0XHQvLyBDcmVhdGUgZ2F1Z2UgaHRtbFxuXHRcdGxldCBnYXVnZUh0bWwgPSAkKCc8ZGl2PicpO1xuXHRcdGdhdWdlQ29udGFpbmVyLmFwcGVuZChnYXVnZUh0bWwpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBnYXVnZVxuXHRcdHRoaXMuX2dhdWdlV2lkZ2V0ID0gdGhpcy5faW5pdEdhdWdlV2lkZ2V0KGdhdWdlSHRtbCwgY2hhcnRIZWlnaHQpO1xuXG5cdFx0Ly8gQXBwZW5kIHRleHQgdG8gZGlzcGxheSBsb2FkXG5cdFx0dGhpcy5fbG9hZFR4dCA9ICQoJzxkaXY+Jywge2NsYXNzOiAndGV4dC1jZW50ZXIgZm9udC13ZWlnaHQtYm9sZCcsIHRleHQ6ICctLS0nfSk7XG5cdFx0Z2F1Z2VDb250YWluZXIuYXBwZW5kKHRoaXMuX2xvYWRUeHQpO1xuXG5cdFx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRcdC8vIFJlc2V0IGRhdGEgc291cmNlXG5cdFx0dGhpcy5yZXNldCgpO1xuXHR9XG5cblx0X2luaXRDaGFydFdpZGdldChjaGFydEh0bWwsIGhlaWdodClcblx0e1xuXHRcdHJldHVybiBjaGFydEh0bWwua2VuZG9DaGFydCh7XG5cdFx0XHR0cmFuc2l0aW9uczogZmFsc2UsXG5cdFx0XHRjaGFydEFyZWE6IHtcblx0XHRcdFx0aGVpZ2h0OiBoZWlnaHQsXG5cdFx0XHRcdGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCdcblx0XHRcdH0sXG5cdCAgICAgICAgbGVnZW5kOiB7XG5cdCAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXNEZWZhdWx0czoge1xuXHQgICAgICAgICAgICB0eXBlOiAnYXJlYScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0lJyxcblx0ICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCdcblx0ICAgICAgICAgICAgfVxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRuYW1lOiAnV29ya2xvYWQnLFxuXHRcdCAgICAgICAgICAgIGZpZWxkOiAnbG9hZCcsXG5cdFx0ICAgICAgICAgICAgY2F0ZWdvcnlGaWVsZDogJ3RpbWUnLFxuXHRcdFx0XHRcdGNvbG9yOiAnIzMzOTlmZicsXG5cdFx0XHRcdFx0bGluZToge1xuXHRcdFx0XHRcdFx0d2lkdGg6IDJcblx0XHRcdFx0XHR9XG5cdFx0ICAgICAgICB9XG5cdFx0XHRdLFxuXHQgICAgICAgIHZhbHVlQXhpczoge1xuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfSUnXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICAgIGxpbmU6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1pbjogMCxcblx0ICAgIFx0XHRtYXg6IDEwMFxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgY2F0ZWdvcnlBeGlzOiB7XG5cdCAgICAgICAgICAgIG1ham9yR3JpZExpbmVzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtYWpvclRpY2tzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fSxcblx0XHRcdFx0bGFiZWxzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fVxuXHQgICAgICAgIH0sXG5cdFx0XHR0b29sdGlwOiB7XG5cdFx0XHRcdHNoYXJlZDogdHJ1ZSxcblx0ICAgICAgICAgICAgdmlzaWJsZTogdHJ1ZSxcblx0XHRcdFx0c2hhcmVkVGVtcGxhdGU6IGdldEJhc2ljU2hhcmVkVGVtcGxhdGUoJ3swfSUnKSxcblx0XHRcdFx0YmFja2dyb3VuZDogJyNlNGU0ZTQnXG5cdCAgICAgICAgfVxuXHQgICAgfSkuZGF0YSgna2VuZG9DaGFydCcpO1xuXHR9XG5cblx0X2luaXRHYXVnZVdpZGdldChnYXVnZUh0bWwsIGhlaWdodClcblx0e1xuXHRcdHJldHVybiBnYXVnZUh0bWwua2VuZG9MaW5lYXJHYXVnZSh7XG5cdFx0XHRwb2ludGVyOiB7XG5cdCAgICAgICAgICAgIHZhbHVlOiAwLFxuXHQgICAgICAgICAgICBzaGFwZTogJ2Fycm93Jyxcblx0ICAgICAgICAgIFx0c2l6ZTogMTAsXG5cdFx0XHRcdGNvbG9yOiAnIzIxMjUyOSdcblx0ICAgICAgICB9LFxuXHRcdFx0Z2F1Z2VBcmVhOiB7XG5cdFx0XHRcdGhlaWdodDogaGVpZ2h0XG5cdFx0XHR9LFxuXHQgICAgICAgIHNjYWxlOiB7XG5cdCAgICAgICAgICAgIG1ham9yVW5pdDogMTAsXG5cdCAgICAgICAgICAgIG1pbm9yVW5pdDogMSxcblx0ICAgICAgICAgICAgbWF4OiAxMDAsXG5cdFx0XHRcdG1pbjogMCxcblx0ICAgICAgICAgICAgcmFuZ2VzOiBbXG5cdCAgICAgICAgICAgICAgICB7XG5cdCAgICAgICAgICAgICAgICAgICAgZnJvbTogMCxcblx0ICAgICAgICAgICAgICAgICAgICB0bzogNTAsXG5cdCAgICAgICAgICAgICAgICAgICAgY29sb3I6ICcjMDBjYzAwJyxcblx0ICAgICAgICAgICAgICAgICAgXHRvcGFjaXR5OiAuNVxuXHQgICAgICAgICAgICAgICAgfSwge1xuXHQgICAgICAgICAgICAgICAgICAgIGZyb206IDUwLFxuXHQgICAgICAgICAgICAgICAgICAgIHRvOiA3NSxcblx0ICAgICAgICAgICAgICAgICAgICBjb2xvcjogJyNmZmUxMDYnLFxuXHQgICAgICAgICAgICAgICAgICBcdG9wYWNpdHk6IC41XG5cdCAgICAgICAgICAgICAgICB9LCB7XG5cdCAgICAgICAgICAgICAgICAgICAgZnJvbTogNzUsXG5cdCAgICAgICAgICAgICAgICAgICAgdG86IDEwMCxcblx0ICAgICAgICAgICAgICAgICAgICBjb2xvcjogJyNlZDE2MDEnLFxuXHQgICAgICAgICAgICAgICAgICBcdG9wYWNpdHk6IC41XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIF0sXG5cdCAgICAgICAgICBcdG1ham9yVGlja3M6IHtcblx0ICAgICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuXHQgICAgICAgICAgICAgIHNpemU6IDEwXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICBcdG1pbm9yVGlja3M6IHtcblx0ICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgXHRsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgXHRsaW5lOiB7XG5cdCAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICAgIFx0cmFuZ2VTaXplOiAxMFxuXHQgICAgICAgIH1cblx0ICAgIH0pLmRhdGEoJ2tlbmRvTGluZWFyR2F1Z2UnKTtcblx0fVxuXG5cdGFkZEVudHJ5KGxvYWQpXG5cdHtcblx0XHQvLyBDSEFSVFxuXG5cdFx0bGV0IG5vdyA9IG5ldyBEYXRlKCk7XG5cblx0XHRsZXQgbmV3RW50cnkgPSB7XG5cdFx0XHR0aW1lOiBnZXRGb3JtYXR0ZWREYXRlVGltZShub3cpLFxuXHRcdFx0dGltZXN0YW1wOiBub3cuZ2V0VGltZSgpLFxuXHRcdFx0bG9hZDogbG9hZFxuXHRcdH07XG5cblx0XHQvLyBBZGQgZW50cnkgdG8gY2hhcnRcblx0XHRzdXBlci5fYWRkRW50cnkobmV3RW50cnkpO1xuXG5cdFx0Ly8gVXBkYXRlIHggYXhpc1xuXHRcdGlmICghdGhpcy5pc1BhdXNlZClcblx0XHRcdHRoaXMuX3VwZGF0ZUVsYXBzZWRUZXh0KCk7XG5cblx0XHQvLyBHQVVHRVxuXG5cdFx0Ly8gRXZhbHVhdGUgYXZlcmFnZVxuXHRcdGxldCBudW1WYWx1ZXMgPSB0aGlzLl9kYXRhU291cmNlLnRvdGFsKCk7XG5cdFx0bGV0IGF2ZXJhZ2VMb2FkID0gMDtcblxuXHRcdGlmIChudW1WYWx1ZXMgPiAwKVxuXHRcdHtcblx0XHRcdGxldCB0b3RhbCA9IDA7XG5cdFx0XHRmb3IgKGxldCBpID0gMDsgaSA8IG51bVZhbHVlczsgaSsrKVxuXHRcdFx0XHR0b3RhbCArPSB0aGlzLl9kYXRhU291cmNlLmF0KGkpLmxvYWQ7XG5cblx0XHRcdGF2ZXJhZ2VMb2FkID0gTWF0aC5yb3VuZCh0b3RhbCAvIG51bVZhbHVlcyk7XG5cdFx0fVxuXG5cdFx0Ly8gU2V0IGdhdWdlIHZhbHVlXG5cdFx0dGhpcy5fZ2F1Z2VXaWRnZXQudmFsdWUoYXZlcmFnZUxvYWQpO1xuXG5cdFx0Ly8gU2V0IGxvYWQgdGV4dFxuXHRcdHRoaXMuX2xvYWRUeHQudGV4dChhdmVyYWdlTG9hZCArICclJylcblx0fVxuXG5cdF91cGRhdGVFbGFwc2VkVGV4dCgpXG5cdHtcblx0XHRsZXQgZHMgPSB0aGlzLl9kYXRhU291cmNlO1xuXG5cdFx0aWYgKGRzLnRvdGFsKCkgPiAxKVxuXHRcdHtcblx0XHRcdC8vIEdldCBheGlzIGxpbWl0c1xuXHRcdFx0Y29uc3QgY2hhcnRNaW5pbXVtID0gZHMuYXQoMCkudGltZXN0YW1wO1xuXHRcdFx0Y29uc3QgY2hhcnRNYXhpbXVtID0gZHMuYXQoZHMudG90YWwoKSAtIDEpLnRpbWVzdGFtcDtcblxuXHRcdFx0Ly8gU2V0IGVsYXBzZWQgdGV4dFxuXHRcdFx0bGV0IHNlY29uZHMgPSBNYXRoLnJvdW5kKCAoY2hhcnRNYXhpbXVtIC0gY2hhcnRNaW5pbXVtKSAvIDEwMDAgKTtcblx0XHRcdGxldCB0aXRsZTtcblxuXHRcdFx0aWYgKHNlY29uZHMgPCA2MClcblx0XHRcdFx0dGl0bGUgPSAnTGFzdCAnICsgKHNlY29uZHMgIT0gMSA/IHNlY29uZHMgKyAnIHNlY29uZHMnIDogJ3NlY29uZCcpO1xuXHRcdFx0ZWxzZVxuXHRcdFx0e1xuXHRcdFx0XHRjb25zdCBtaW51dGVzID0gTWF0aC5mbG9vcihzZWNvbmRzIC8gNjApO1xuXHRcdFx0XHR0aXRsZSA9ICdMYXN0ICcgKyAobWludXRlcyAhPSAxID8gbWludXRlcyArICcgbWludXRlcycgOiAnbWludXRlJyk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2VsYXBzZWRUeHQudGV4dCh0aXRsZSk7XG5cdFx0fVxuXHR9XG5cblx0Z2V0IGxvYWQoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2F2ZXJhZ2VMb2FkO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnc3lzdGVtLXdvcmtsb2FkLWNoYXJ0JykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ3N5c3RlbS13b3JrbG9hZC1jaGFydCcsIFN5c3RlbVdvcmtsb2FkQ2hhcnQpO1xuIiwiaW1wb3J0IHtCYXNlQ2hhcnR9IGZyb20gJy4vYmFzZS1jaGFydCc7XG5cbmltcG9ydCB7Z2V0QmFzaWNTaGFyZWRUZW1wbGF0ZSwgZ2V0Rm9ybWF0dGVkRGF0ZVRpbWV9IGZyb20gJy4vY2hhcnQtdXRpbHMnO1xuXG5leHBvcnQgY2xhc3MgVGhyZWFkQ291bnRDaGFydCBleHRlbmRzIEJhc2VDaGFydFxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKDEyMCk7XG5cdH1cblxuXHRfaW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbClcblx0e1xuXHRcdHJldHVybiBjaGFydEh0bWwua2VuZG9DaGFydCh7XG5cdFx0XHR0cmFuc2l0aW9uczogZmFsc2UsXG5cdFx0XHRjaGFydEFyZWE6IHtcblx0XHRcdFx0aGVpZ2h0OiAxMjAsXG5cdFx0XHRcdGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCdcblx0XHRcdH0sXG5cdCAgICAgICAgbGVnZW5kOiB7XG5cdCAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXNEZWZhdWx0czoge1xuXHQgICAgICAgICAgICB0eXBlOiAnYXJlYScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nLFxuXHQgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRuYW1lOiAnVGhyZWFkcycsXG5cdFx0ICAgICAgICAgICAgZmllbGQ6ICd0aHJlYWRzJyxcblx0XHQgICAgICAgICAgICBjYXRlZ29yeUZpZWxkOiAndGltZScsXG5cdFx0XHRcdFx0Y29sb3I6IHRoaXMudGhyZWFkc0NvbG9yLFxuXHRcdFx0XHRcdGxpbmU6IHtcblx0XHRcdFx0XHRcdHdpZHRoOiAyXG5cdFx0XHRcdFx0fVxuXHRcdCAgICAgICAgfVxuXHRcdFx0XSxcblx0ICAgICAgICB2YWx1ZUF4aXM6IHtcblx0XHRcdFx0bWluOiAwLFxuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfSdcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICAgICAgbGluZToge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICB9LFxuXHQgICAgICAgIGNhdGVnb3J5QXhpczoge1xuXHQgICAgICAgICAgICBtYWpvckdyaWRMaW5lczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWFqb3JUaWNrczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGxhYmVsczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHRcdFx0dG9vbHRpcDoge1xuXHRcdFx0XHRzaGFyZWQ6IHRydWUsXG5cdCAgICAgICAgICAgIHZpc2libGU6IHRydWUsXG5cdFx0XHRcdHNoYXJlZFRlbXBsYXRlOiBnZXRCYXNpY1NoYXJlZFRlbXBsYXRlKCksXG5cdFx0XHRcdGJhY2tncm91bmQ6ICcjZTRlNGU0J1xuXHQgICAgICAgIH1cblx0ICAgIH0pLmRhdGEoJ2tlbmRvQ2hhcnQnKTtcblx0fVxuXG5cdGdldCB0aHJlYWRzQ29sb3IoKVxuXHR7XG5cdFx0cmV0dXJuICcjMzM5OUZGJztcblx0fVxuXG5cdGFkZEVudHJ5KHRocmVhZHMpXG5cdHtcblx0XHRsZXQgbmV3RW50cnkgPSB7XG5cdFx0XHR0aW1lOiBnZXRGb3JtYXR0ZWREYXRlVGltZShuZXcgRGF0ZSgpKSxcblx0XHRcdHRocmVhZHM6IHRocmVhZHNcblx0XHR9O1xuXG5cdFx0Ly8gQWRkIGVudHJ5IHRvIGNoYXJ0XG5cdFx0c3VwZXIuX2FkZEVudHJ5KG5ld0VudHJ5KTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ3RocmVhZC1jb3VudC1jaGFydCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCd0aHJlYWQtY291bnQtY2hhcnQnLCBUaHJlYWRDb3VudENoYXJ0KTtcbiIsImltcG9ydCB7QmFzZU1vZHVsZX0gZnJvbSAnLi9iYXNlLW1vZHVsZSc7XG5pbXBvcnQge2J5dGVzVG9TaXplLCBrQnl0ZXNUb1NpemV9IGZyb20gJy4uL3V0aWxzL3V0aWxpdGllcyc7XG5pbXBvcnQge2dldFRpbWVSYW5nZVRvb2x0aXBUZW1wbGF0ZX0gZnJvbSAnLi4vY29tcG9uZW50cy9jaGFydHMvY2hhcnQtdXRpbHMnO1xuaW1wb3J0IHtDcHVVc2FnZUNoYXJ0fSBmcm9tICcuLi9jb21wb25lbnRzL2NoYXJ0cy9jcHUtdXNhZ2UtY2hhcnQnO1xuaW1wb3J0IHtUaHJlYWRDb3VudENoYXJ0fSBmcm9tICcuLi9jb21wb25lbnRzL2NoYXJ0cy90aHJlYWQtY291bnQtY2hhcnQnO1xuaW1wb3J0IHtNZW1vcnlDaGFydH0gZnJvbSAnLi4vY29tcG9uZW50cy9jaGFydHMvbWVtb3J5LWNoYXJ0JztcbmltcG9ydCB7TmV0d29ya1JlYWx0aW1lQ2hhcnR9IGZyb20gJy4uL2NvbXBvbmVudHMvY2hhcnRzL25ldHdvcmstcmVhbHRpbWUtY2hhcnQnO1xuaW1wb3J0IHtOZXR3b3JrMjRoQ2hhcnR9IGZyb20gJy4uL2NvbXBvbmVudHMvY2hhcnRzL25ldHdvcmstMjRoLWNoYXJ0JztcbmltcG9ydCB7U3lzdGVtV29ya2xvYWRDaGFydH0gZnJvbSAnLi4vY29tcG9uZW50cy9jaGFydHMvc3lzdGVtLXdvcmtsb2FkLWNoYXJ0JztcbmltcG9ydCB7U3lzdGVtUXVldWVDaGFydH0gZnJvbSAnLi4vY29tcG9uZW50cy9jaGFydHMvc3lzdGVtLXF1ZXVlLWNoYXJ0JztcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRGFzaGJvYXJkIGV4dGVuZHMgQmFzZU1vZHVsZVxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKCdkYXNoYm9hcmQnKTtcblxuXHRcdC8vIE91dGdvaW5nIHJlcXVlc3RzXG5cdFx0dGhpcy5SRVFfSU5JVCA9ICdpbml0Jztcblx0XHR0aGlzLlJFUV9HRVRfREFUQSA9ICdnZXREYXRhJztcblx0XHR0aGlzLlJFUV9EVU1QX1RIUkVBRFMgPSAnZ2V0VGhEdW1wJztcblxuXHRcdC8vIEluY29taW5nIHJlc3BvbnNlc1xuXHRcdHRoaXMuUkVTUF9JTklUID0gJ2luaXQnO1xuXHRcdHRoaXMuUkVTUF9EQVRBID0gJ2RhdGEnO1xuXHRcdHRoaXMuUkVTUF9USFJFQURfRFVNUCA9ICd0aER1bXAnO1xuXG5cdFx0dGhpcy5fdGNwT3V0VGhyZWFkcyA9IDA7XG5cdFx0dGhpcy5fdGNwT3V0TG9hZCA9IDA7XG5cdFx0dGhpcy5fdWRwT3V0VGhyZWFkcyA9IDA7XG5cdFx0dGhpcy5fdWRwT3V0TG9hZCA9IDA7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBDT01NT04gTU9EVUxFIElOVEVSRkFDRSBNRVRIT0RTXG5cdC8vIFRoaXMgbWVtYmVycyBhcmUgdXNlZCBieSB0aGUgbWFpbiBjb250cm9sbGVyXG5cdC8vIHRvIGNvbW11bmljYXRlIHdpdGggdGhlIG1vZHVsZSdzIGNvbnRyb2xsZXIuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0aW5pdGlhbGl6ZShpZERhdGEsIHNoZWxsQ29udHJvbGxlcilcblx0e1xuXHRcdC8vIENhbGwgc3VwZXIgbWV0aG9kXG5cdFx0c3VwZXIuaW5pdGlhbGl6ZShpZERhdGEsIHNoZWxsQ29udHJvbGxlcik7XG5cblx0XHQvLyBJbml0aWFsaXplIHNjcm9sbGluZyB0YWJzXG5cdFx0JCgnI2RzaC10YWJOYXZpZ2F0b3IgPiAjdGFicycpLnNjcm9sbGluZ1RhYnMoe1xuXHRcdFx0Ym9vdHN0cmFwVmVyc2lvbjogNCxcblx0XHRcdHNjcm9sbFRvVGFiRWRnZTogdHJ1ZSxcblx0XHRcdGVuYWJsZVN3aXBpbmc6IHRydWUsXG5cdFx0XHRkaXNhYmxlU2Nyb2xsQXJyb3dzT25GdWxseVNjcm9sbGVkOiB0cnVlLFxuXHRcdFx0Y3NzQ2xhc3NMZWZ0QXJyb3c6ICdmYSBmYS1jaGV2cm9uLWxlZnQnLFxuXHRcdFx0Y3NzQ2xhc3NSaWdodEFycm93OiAnZmEgZmEtY2hldnJvbi1yaWdodCdcblx0XHR9KTtcblxuXHRcdC8vIEluaXRpYWxpemUgaW50ZXJ2YWwgZHJvcGRvd25cblx0XHR0aGlzLl9pbnRlcnZhbERyb3BEb3duID0gJCgnI2RzaC1pbnRlcnZhbEREJykua2VuZG9Ecm9wRG93bkxpc3Qoe1xuXHRcdFx0dmFsdWVUZW1wbGF0ZTogJzxzcGFuIGNsYXNzPVwidGV4dC1tdXRlZCBwci0xXCI+SW50ZXJ2YWw6PC9zcGFuPjxzcGFuPiM6ZGF0YS50ZXh0Izwvc3Bhbj4nLFxuXHRcdFx0Y2hhbmdlOiAkLnByb3h5KHRoaXMuX29uVXBkYXRlSW50ZXJ2YWxDaGFuZ2UsIHRoaXMpXG5cdFx0fSkuZGF0YSgna2VuZG9Ecm9wRG93bkxpc3QnKTtcblxuXHRcdC8vIEluaXRpYWxpemUgdGhyZWFkcyBncmlkXG5cdFx0dGhpcy5fdGhyZWFkc0dyaWQgPSAkKCcjZHNoLXRocmVhZHNHcmlkJykua2VuZG9HcmlkKHtcblx0XHRcdGRhdGFTb3VyY2U6IHRoaXMuX2dldFRocmVhZHNHcmlkRGF0YVNvdXJjZSgpLFxuXHRcdFx0c2Nyb2xsYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHNvcnRhYmxlOiB0cnVlLFxuICAgICAgICAgICAgZmlsdGVyYWJsZTogZmFsc2UsXG5cdFx0XHRyZXNpemFibGU6IHRydWUsXG5cdFx0XHRzZWxlY3RhYmxlOiBmYWxzZSxcblx0XHRcdGNvbHVtbnM6IFtcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGZpZWxkOiAnaWQnLFxuXHRcdFx0XHRcdHRpdGxlOiAnSWQnLFxuXHRcdFx0XHRcdHdpZHRoOiA2MFxuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0ZmllbGQ6ICduYW1lJyxcblx0XHRcdFx0XHR0aXRsZTogJ05hbWUnLFxuXHRcdFx0XHRcdHdpZHRoOiAnNjUlJ1xuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0ZmllbGQ6ICdjcHVUaW1lJyxcblx0XHRcdFx0XHR0aXRsZTogJ0NQVSBUaW1lJyxcblx0XHRcdFx0XHRmb3JtYXQ6ICd7MH0lJyxcblx0XHRcdFx0XHR3aWR0aDogJzM1JSdcblx0XHRcdFx0fSxcblx0XHRcdF0sXG5cdFx0XHRub1JlY29yZHM6IHtcblx0XHRcdFx0dGVtcGxhdGU6ICdObyB0aHJlYWRzLidcblx0XHRcdH0sXG5cdFx0XHRoZWlnaHQ6ICdjYWxjKDI0MHB4IC0gLjc1cmVtICsgMXJlbSknXG5cdFx0fSkuZGF0YSgna2VuZG9HcmlkJyk7XG5cblx0XHQvLyBBZGQgY2xpY2sgbGlzdGVuZXIgdG8gdGhyZWFkcyBkdW1wIGJ1dHRvblxuXHRcdCQoJyNkc2gtZHVtcFRocmVhZHNCdCcpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25EdW1wVGhyZWFkc0NsaWNrLCB0aGlzKSk7XG5cblx0XHQvLyBDb25maWd1cmUgdGhyZWFkIGR1bXAgcGFuZWxcblx0XHQkKCcjZHNoLXRocmVhZER1bXBNb2RhbCcpLm1vZGFsKHtcblx0XHRcdGJhY2tkcm9wOiAnc3RhdGljJyxcblx0XHRcdGtleWJvYXJkOiBmYWxzZSxcblx0XHRcdHNob3c6IGZhbHNlLFxuXHRcdH0pO1xuXG5cdFx0Ly8gQWRkIGxpc3RlbmVyIGZvciB0aHJlYWRzIGR1bXAgcGFuZWwgaGlkZVxuXHRcdCQoJyNkc2gtdGhyZWFkRHVtcE1vZGFsJykub24oJ2hpZGRlbi5icy5tb2RhbCcsICQucHJveHkodGhpcy5fb25UaHJlYWREdW1wTW9kYWxIaWRkZW4sIHRoaXMpKTtcblxuXHRcdC8vIEFkZCBjbGljayBsaXN0ZW5lciB0byB0aHJlYWRzIGR1bXAgY29weSBidXR0b25cblx0XHQkKCcjZHNoLWNvcHlUaHJlYWREdW1wQnQnKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uQ29weVRocmVhZER1bXBDbGljaywgdGhpcykpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSB0aW1lIHJhbmdlIHNsaWRlclxuXHRcdHRoaXMuX3RpbWVTbGlkZXIgPSAkKCcjZHNoLXRpbWVTbGlkZXInKS5rZW5kb1JhbmdlU2xpZGVyKHtcblx0XHRcdG1pbjogLTI0LFxuICAgICAgICAgICAgbWF4OiAwLFxuICAgICAgICAgICAgc21hbGxTdGVwOiAxLFxuICAgICAgICAgICAgbGFyZ2VTdGVwOiAwLFxuXHRcdFx0Y2hhbmdlOiAkLnByb3h5KHRoaXMuX29uVGltZVJhbmdlQ2hhbmdlLCB0aGlzKSxcblx0XHRcdHRvb2x0aXA6IHtcblx0XHRcdFx0dGVtcGxhdGU6IGdldFRpbWVSYW5nZVRvb2x0aXBUZW1wbGF0ZSgpXG5cdFx0XHR9LFxuXHRcdFx0bGVmdERyYWdIYW5kbGVUaXRsZTogJ0RyYWcnLFxuXHRcdFx0cmlnaHREcmFnSGFuZGxlVGl0bGU6ICdEcmFnJyxcblx0XHR9KS5kYXRhKCdrZW5kb1JhbmdlU2xpZGVyJyk7XG5cblx0XHQvLyBBZGQgY2xpY2sgbGlzdGVuZXIgdG8gcmVzZXQgY2hhcnRzIGJ1dHRvblxuXHRcdCQoJyNkc2gtcmVzZXRCdCcpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25SZXNldENoYXJ0c0NsaWNrLCB0aGlzKSk7XG5cblx0XHQvLyBBZGQgY2xpY2sgbGlzdGVuZXIgdG8gcGxheSAmIHBhdXNlIGNoYXJ0IHVwZGF0ZSBidXR0b25zXG5cdFx0JCgnI2RzaC1wYXVzZUJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vblBhdXNlVXBkYXRlQ2xpY2ssIHRoaXMpKTtcblx0XHQkKCcjZHNoLXBsYXlCdCcpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25QbGF5VXBkYXRlQ2xpY2ssIHRoaXMpKTtcblxuXHRcdC8vIFNldCByZWZlcmVuY2UgdG8gY2hhcnRzXG5cdFx0dGhpcy5fY3B1VXNhZ2VDaGFydCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdkc2gtY3B1VXNhZ2VDaGFydCcpO1xuXHRcdHRoaXMuX3RocmVhZENvdW50Q2hhcnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZHNoLXRocmVhZENvdW50Q2hhcnQnKTtcblx0XHR0aGlzLl9tZW1vcnlDaGFydCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdkc2gtbWVtb3J5Q2hhcnQnKTtcblx0XHR0aGlzLl9uZXR3b3JrUlRDaGFydCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdkc2gtbmV0d29ya1JUQ2hhcnQnKTtcblx0XHR0aGlzLl9uZXR3b3JrMjRoQ2hhcnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZHNoLW5ldHdvcmsyNGhDaGFydCcpO1xuXHRcdHRoaXMuX3N5c1dvcmtsb2FkQ2hhcnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZHNoLXN5c3RlbVdvcmtsb2FkQ2hhcnQnKTtcblx0XHR0aGlzLl9vdXRUY3BNc2dRdWV1ZUNoYXJ0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2RzaC1vdXRnb2luZ1RjcE1lc3NhZ2VzUXVldWVDaGFydCcpO1xuXHRcdHRoaXMuX291dFVkcE1zZ1F1ZXVlQ2hhcnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZHNoLW91dGdvaW5nVWRwTWVzc2FnZXNRdWV1ZUNoYXJ0Jyk7XG5cdFx0dGhpcy5fc3lzUXVldWVDaGFydCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdkc2gtc3lzdGVtUXVldWVDaGFydCcpO1xuXHRcdHRoaXMuX2V4dFF1ZXVlQ2hhcnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnZHNoLWV4dGVuc2lvblF1ZXVlQ2hhcnQnKTtcblxuXHRcdC8vIFNldCBjb2xvcnMgaW4gY2hhcnQgbGVnZW5kc1xuXHRcdCQoJyNkc2gtc3lzdGVtTG9hZENvbG9yJykuY3NzKCdjb2xvcicsIHRoaXMuX2NwdVVzYWdlQ2hhcnQuc3lzdGVtQ29sb3IpO1xuXHRcdCQoJyNkc2gtcHJvY2Vzc0xvYWRDb2xvcicpLmNzcygnY29sb3InLCB0aGlzLl9jcHVVc2FnZUNoYXJ0LnByb2Nlc3NDb2xvcik7XG5cdFx0JCgnI2RzaC1hbGxvY01lbUNvbG9yJykuY3NzKCdjb2xvcicsIHRoaXMuX21lbW9yeUNoYXJ0LmFsbG9jYXRlZENvbG9yKTtcblx0XHQkKCcjZHNoLXVzZWRNZW1Db2xvcicpLmNzcygnY29sb3InLCB0aGlzLl9tZW1vcnlDaGFydC51c2VkQ29sb3IpO1xuXHRcdCQoJyNkc2gtaW5jb21pbmdOZXRDb2xvcicpLmNzcygnY29sb3InLCB0aGlzLl9uZXR3b3JrUlRDaGFydC5pbmNvbWluZ0NvbG9yKTtcblx0XHQkKCcjZHNoLW91dGdvaW5nTmV0Q29sb3InKS5jc3MoJ2NvbG9yJywgdGhpcy5fbmV0d29ya1JUQ2hhcnQub3V0Z29pbmdDb2xvcik7XG5cblx0XHQvLyBSZXNldCB0aW1lIHJhbmdlIG9uIDI0aCBuZXR3b3JrIGNoYXJ0XG5cdFx0dGhpcy5fb25UaW1lUmFuZ2VDaGFuZ2UoKTtcblxuXHRcdC8vIEFkZCBsaXN0ZW5lciB0byByZWRyYXcgYWxsIGNoYXJ0cyBvbiBtYWluIHRhYiBjaGFuZ2Vcblx0XHQvLyAodG8gd29yayBhcm91bmQgYW4gaXNzdWUgd2l0aCB0aGUgY2hhcnQgcmVzaXppbmcgdG8gZGVmYXVsdCB3aWR0aCB3aGVuIHBhbmUgaXMgaGlkZGVuKVxuXHRcdCQoJ2FbZGF0YS10b2dnbGU9XCJ0YWJcIl0nKS5vbignc2hvd24uYnMudGFiJywgJC5wcm94eSh0aGlzLl9vbldpbmRvd1Jlc2l6ZSwgdGhpcykpO1xuXG5cdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIHJlZHJhdyBuZXR3b3JrIGNoYXJ0cyBvbiBuZXR3b3JrIHRhYiBjaGFuZ2Vcblx0XHQvLyAodG8gd29yayBhcm91bmQgYW4gaXNzdWUgd2l0aCB0aGUgY2hhcnQgcmVzaXppbmcgdG8gZGVmYXVsdCB3aWR0aCB3aGVuIHBhbmUgaXMgaGlkZGVuKVxuXHRcdCQoJyNkc2gtbmV0d29ya1BpbGxzIGFbZGF0YS10b2dnbGU9XCJwaWxsXCJdJykub24oJ3Nob3duLmJzLnRhYicsICQucHJveHkodGhpcy5fcmVkcmF3TmV0d29ya0NoYXJ0cywgdGhpcykpO1xuXG5cdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIHJlZHJhdyBvdXRnb2luZyBtZXNzYWdlcyBxdWV1ZSBjaGFydHMgb24gdGFiIGNoYW5nZVxuXHRcdC8vICh0byB3b3JrIGFyb3VuZCBhbiBpc3N1ZSB3aXRoIHRoZSBjaGFydCByZXNpemluZyB0byBkZWZhdWx0IHdpZHRoIHdoZW4gcGFuZSBpcyBoaWRkZW4pXG5cdFx0JCgnI2RzaC1tc2dRdWV1ZVBpbGxzIGFbZGF0YS10b2dnbGU9XCJwaWxsXCJdJykub24oJ3Nob3duLmJzLnRhYicsICQucHJveHkodGhpcy5fcmVkcmF3T3V0TXNnQ2hhcnRzLCB0aGlzKSk7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXIgdG8gcmVkcmF3IGFsbCBjaGFydHMgaW4gY2FzZSBvZiB3aW5kb3cgcmVzaXplXG5cdFx0JCh3aW5kb3cpLm9uKCdyZXNpemUnLCAkLnByb3h5KHRoaXMuX29uV2luZG93UmVzaXplLCB0aGlzKSk7XG5cdFx0dGhpcy5fb25XaW5kb3dSZXNpemUoKTsgLy8gQWxzbyBkbyBpdCBpbW1lZGlhdGVseVxuXG5cdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIHNob3cgaGVscCB0b29sdGlwcyBpbiBxdWV1ZXMgc3RhdHVzIHRhYlxuXHRcdCQoJyNkc2gtcXVldWVzJykua2VuZG9Ub29sdGlwKHtcblx0XHRcdGZpbHRlcjogJ2lbdGl0bGVdLmhlbHAnLFxuXHRcdFx0cG9zaXRpb246ICdyaWdodCcsXG5cdFx0XHR3aWR0aDogJzI1MHB4Jyxcblx0XHRcdGNvbnRlbnQ6IGZ1bmN0aW9uKGUpIHtcblx0XHRcdFx0cmV0dXJuIGA8ZGl2IGNsYXNzPVwiaGVscC10b29sdGlwXCI+JHtlLnRhcmdldC5kYXRhKCd0aXRsZScpfTwvZGl2PmA7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXIgdG8gcmVnZW5lcmF0ZSBsaW5rIHRvIG9wZW4gd2ViIHNlcnZlciBleHRlcm5hbCBtYW5hZ2VyIGNvbnNvbGVcblx0XHQkKCcjZHNoLXVzZUh0dHBzQ2hlY2snKS5vbignY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblVzZUh0dHBzRm9yV3NNYW5hZ2VyQ2hhbmdlLCB0aGlzKSk7XG5cblx0XHQvLyBTZW5kIGluaXRpYWxpemF0aW9uIHJlcXVlc3Rcblx0XHR0aGlzLnNlbmRFeHRlbnNpb25SZXF1ZXN0KHRoaXMuUkVRX0lOSVQpO1xuXHR9XG5cblx0ZGVzdHJveSgpXG5cdHtcblx0XHQvLyBDYWxsIHN1cGVyIG1ldGhvZFxuXHRcdHN1cGVyLmRlc3Ryb3koKTtcblxuXHRcdC8vIERlc3Ryb3kgc2Nyb2xsaW5nIHRhYnNcblx0XHQkKCcjZHNoLXRhYk5hdmlnYXRvciAjdGFicycpLnNjcm9sbGluZ1RhYnMoJ2Rlc3Ryb3knKTtcblxuXHRcdC8vIFJlbW92ZSBvdGhlciBsaXN0ZW5lcnNcblx0XHQkKCcjZHNoLXJlc2V0QnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI2RzaC1wYXVzZUJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyNkc2gtcGxheUJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyNkc2gtZHVtcFRocmVhZHNCdCcpLm9mZignY2xpY2snKTtcblx0XHQkKCdhW2RhdGEtdG9nZ2xlPVwidGFiXCJdJykub2ZmKCdzaG93bi5icy50YWInKTtcblx0XHQkKCdhW2RhdGEtdG9nZ2xlPVwicGlsbFwiXScpLm9mZignc2hvd24uYnMudGFiJyk7XG5cdFx0JCh3aW5kb3cpLm9mZigncmVzaXplJyk7XG5cdFx0JCgnI2RzaC11c2VIdHRwc0NoZWNrJykub2ZmKCdjaGFuZ2UnKTtcblxuXHRcdC8vIFJlbW92ZSB0aHJlYWQgZHVtcCBwYW5lbCBsaXN0ZW5lclxuXHRcdCQoJyNkc2gtdGhyZWFkRHVtcE1vZGFsJykub2ZmKCdoaWRkZW4uYnMubW9kYWwnKTtcblxuXHRcdC8vIENsZWFyIHJlcXVlc3Qgc2NoZWR1bGluZ1xuXHRcdGNsZWFyVGltZW91dCh0aGlzLl9yZXF1ZXN0VGltZXIpO1xuXHR9XG5cblx0b25FeHRlbnNpb25Db21tYW5kKGNvbW1hbmQsIGRhdGEpXG5cdHtcblx0XHQvLyBJbml0aWFsaXphdGlvbiBkYXRhIHJlY2VpdmVkXG5cdFx0aWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX0lOSVQpXG5cdFx0e1xuXHRcdFx0Ly8gU2VydmVyIHNlbmRzIGZsYWdzIGluZGljYXRpbmcgaWYgd2ViIHNlcnZlcidzIGludGVybmFsIG1hbmFnZXIgaXMgYWNjZXNzaWJsZSBhbmQgaG93XG5cdFx0XHR0aGlzLl93c01hbmFnZXJDb25maWcgPSB7XG5cdFx0XHRcdGhhc0FjY2VzczogZGF0YS5nZXRCb29sKCdoYXNXc01hbmFnZXInKSxcblx0XHRcdFx0aHR0cEVuYWJsZWQ6IGRhdGEuZ2V0Qm9vbCgnaHR0cEVuYWJsZWQnKSxcblx0XHRcdFx0aHR0cHNFbmFibGVkOiBkYXRhLmdldEJvb2woJ2h0dHBzRW5hYmxlZCcpLFxuXHRcdFx0XHRodHRwUG9ydDogZGF0YS5nZXRJbnQoJ2h0dHBQb3J0JyksXG5cdFx0XHRcdGh0dHBzUG9ydDogZGF0YS5nZXRJbnQoJ2h0dHBzUG9ydCcpLFxuXHRcdFx0fVxuXG5cdFx0XHQvLyBFbmFibGUgYWNjZXNzIHRvIHdlYiBzZXJ2ZXIgbWFuYWdlciBjb25zb2xlXG5cdFx0XHR0aGlzLl9lbmFibGVXZWJTZXJ2ZXJNYW5hZ2VyQWNjZXNzKCk7XG5cblx0XHRcdC8vIFJlcXVlc3QgZGF0YSB0byBzZXJ2ZXJcblx0XHRcdHRoaXMuX3JlcXVlc3REYXRhKHRydWUpO1xuXHRcdH1cblxuXHRcdC8vIERhdGEgcmVjZWl2ZWRcblx0XHRlbHNlIGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9EQVRBKVxuXHRcdHtcblx0XHRcdC8vIENQVSBMT0FEIENIQVJUXG5cblx0XHRcdHRoaXMuX2NwdVVzYWdlQ2hhcnQuYWRkRW50cnkoZGF0YS5nZXREb3VibGUoJ3BDcHUnKSwgZGF0YS5nZXREb3VibGUoJ3NDcHUnKSk7XG5cdFx0XHQkKCcjZHNoLXN5c3RlbUxvYWRMYWJlbCcpLnRleHQoZGF0YS5nZXREb3VibGUoJ3NDcHUnKSk7XG5cdFx0XHQkKCcjZHNoLXByb2Nlc3NMb2FkTGFiZWwnKS50ZXh0KGRhdGEuZ2V0RG91YmxlKCdwQ3B1JykpO1xuXG5cdFx0XHQvLyBBcyBzeXN0ZW0gY3B1IGxvYWQgaXMgbm90IGFsd2F5cyBhdmFpbGFibGUgKGZvciBleGFtcGxlIG9uIE1hY09TIFgpLCBsZXQncyBoaWRlIGl0IGluIGNhc2UgaXQgaXNuJ3Rcblx0XHRcdGlmIChkYXRhLmdldERvdWJsZSgnc0NwdScpIDwgMClcblx0XHRcdFx0JCgnI2RzaC1zeXN0ZW1Mb2FkTGVnZW5kJykuaGlkZSgpO1xuXG5cdFx0XHQvLyBUSFJFQURTIENPVU5UIENIQVJUXG5cblx0XHRcdGNvbnN0IHRocmVhZENvdW50ID0gZGF0YS5nZXRTRlNBcnJheSgndGhMaXN0Jykuc2l6ZSgpO1xuXHRcdFx0dGhpcy5fdGhyZWFkQ291bnRDaGFydC5hZGRFbnRyeSh0aHJlYWRDb3VudCk7XG5cdFx0XHQkKCcjZHNoLXRocmVhZHNDb3VudExhYmVsJykudGV4dCh0aHJlYWRDb3VudCk7XG5cblx0XHRcdC8vIE1FTU9SWSBVU0FHRSBDSEFSVFxuXHRcdFx0Ly8gTk9URTogbWVtb3J5IGRhdGEgaXMgc2VudCBhcyBCeXRlcyBieSB0aGUgc2VydmVyXG5cblx0XHRcdGNvbnN0IGZyZWVNZW0gPSBkYXRhLmdldExvbmcoJ2ZyZWVNZW0nKTtcblx0XHRcdGNvbnN0IG1heE1lbSA9IGRhdGEuZ2V0TG9uZygnbWF4TWVtJyk7XG5cdFx0XHRjb25zdCB0b3RhbE1lbSA9IGRhdGEuZ2V0TG9uZygndG90YWxNZW0nKTtcblx0XHRcdGNvbnN0IHVzZWRNZW0gPSB0b3RhbE1lbSAtIGZyZWVNZW07XG5cblx0XHRcdHRoaXMuX21lbW9yeUNoYXJ0LmFkZEVudHJ5KHRvdGFsTWVtLCB1c2VkTWVtKTtcblx0XHRcdCQoJyNkc2gtbWF4TWVtb3J5TGFiZWwnKS50ZXh0KHRoaXMuX2dldE1lbU9iamVjdChtYXhNZW0pLmxhYmVsKTtcblx0XHRcdCQoJyNkc2gtZnJlZU1lbW9yeUxhYmVsJykudGV4dCh0aGlzLl9nZXRNZW1PYmplY3QoZnJlZU1lbSkubGFiZWwpO1xuXG5cdFx0XHQvLyBUSFJFQURTIExJU1RcblxuXHRcdFx0Y29uc3QgdG90YWxUaHJlYWRDcHVUaW1lID0gZGF0YS5nZXRMb25nKCd0aENwdScpO1xuXHRcdFx0bGV0IHRocmVhZHMgPSBbXTtcblxuXHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBkYXRhLmdldFNGU0FycmF5KCd0aExpc3QnKS5zaXplKCk7IGkrKylcblx0XHRcdHtcblx0XHRcdFx0bGV0IHRocmVhZERhdGEgPSBkYXRhLmdldFNGU0FycmF5KCd0aExpc3QnKS5nZXRTRlNPYmplY3QoaSk7XG5cblx0XHRcdFx0dGhyZWFkcy5wdXNoKHtcblx0XHRcdFx0XHRpZDogdGhyZWFkRGF0YS5nZXRMb25nKCdpZCcpLFxuXHRcdFx0XHRcdG5hbWU6IHRocmVhZERhdGEuZ2V0VXRmU3RyaW5nKCduYW1lJyksXG5cdFx0XHRcdFx0Y3B1VGltZTogTWF0aC5yb3VuZCh0aHJlYWREYXRhLmdldExvbmcoJ2NwdScpIC8gdG90YWxUaHJlYWRDcHVUaW1lICogMTAwMCkgLyAxMFxuXHRcdFx0XHR9KTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU3Vic3RpdHV0ZSBncmlkJ3MgZGF0YSBzb3VyY2UsIHJldGFpbmluZyBjdXJyZW50IHNvcnRpbmdcblx0XHRcdGxldCBjdXJyU29ydCA9IHRoaXMuX3RocmVhZHNHcmlkLmRhdGFTb3VyY2Uuc29ydCgpO1xuXHRcdFx0dGhpcy5fdGhyZWFkc0dyaWQuc2V0RGF0YVNvdXJjZSh0aGlzLl9nZXRUaHJlYWRzR3JpZERhdGFTb3VyY2UodGhyZWFkcywgY3VyclNvcnQpKTtcblxuXHRcdFx0Ly8gTkVUV09SSyBUUkFGRklDXG5cdFx0XHQvLyBOT1RFOiBuZXR3b3JrIHRyYWZmaWMgZGF0YSBpcyBzZW50IGFzIEtCeXRlcyBieSB0aGUgc2VydmVyXG5cblx0XHRcdGlmIChkYXRhLmNvbnRhaW5zS2V5KCdudE91dEhpc3RvcnknKSlcblx0XHRcdHtcblx0XHRcdFx0Y29uc3Qgb3V0Z29pbmdEYXRhID0gZGF0YS5nZXRMb25nQXJyYXkoJ250T3V0SGlzdG9yeScpO1xuXHRcdFx0XHRjb25zdCBpbmNvbWluZ0RhdGEgPSBkYXRhLmdldExvbmdBcnJheSgnbnRJbkhpc3RvcnknKTtcblx0XHRcdFx0Y29uc3Qgc2FtcGxpbmdSYXRlTWlucyA9IGRhdGEuZ2V0SW50KCdudFJhdGUnKTtcblx0XHRcdFx0Y29uc3Qgc2hpZnRTZWNvbmRzID0gZGF0YS5nZXRJbnQoJ250U2hpZnQnKTtcblxuXHRcdFx0XHR0aGlzLl9uZXR3b3JrMjRoQ2hhcnQuYWRkSGlzdG9yeUVudHJpZXMob3V0Z29pbmdEYXRhLCBpbmNvbWluZ0RhdGEsIHNhbXBsaW5nUmF0ZU1pbnMgKiA2MCwgc2hpZnRTZWNvbmRzKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQWRkIGN1cnJlbnQgdmFsdWVzXG5cdFx0XHR0aGlzLl9uZXR3b3JrMjRoQ2hhcnQuYWRkRW50cnkoZGF0YS5nZXRMb25nKCdudE91dCcpLCBkYXRhLmdldExvbmcoJ250SW4nKSk7XG5cdFx0XHR0aGlzLl9uZXR3b3JrUlRDaGFydC5hZGRFbnRyeShkYXRhLmdldExvbmcoJ250T3V0JyksIGRhdGEuZ2V0TG9uZygnbnRJbicpKTtcblxuXHRcdFx0Ly8gVFJBRkZJQyBERVRBSUxTXG5cblx0XHRcdC8vIFNlc3Npb25zXG5cdFx0XHQkKCcjZHNoLWRldFNlc3Npb25zQ3VycmVudCcpLnRleHQoJ0N1cnJlbnQ6ICcgKyAoZGF0YS5nZXRJbnQoJ3NTb2NrZXQnKSArIGRhdGEuZ2V0SW50KCdzSHR0cCcpKSk7XG5cdFx0XHQkKCcjZHNoLWRldFNlc3Npb25zTWF4JykudGV4dCgnTWF4OiAnICsgZGF0YS5nZXRJbnQoJ2Njc01heCcpKTtcblx0XHRcdCQoJyNkc2gtZGV0U2Vzc2lvbnNTb2NrZXQnKS50ZXh0KCdTb2NrZXQ6ICcgKyBkYXRhLmdldEludCgnc1NvY2tldCcpKTtcblx0XHRcdCQoJyNkc2gtZGV0U2Vzc2lvbnNIdHRwJykudGV4dCgnSHR0cDogJyArIGRhdGEuZ2V0SW50KCdzSHR0cCcpKTtcblxuXHRcdFx0Ly8gVXNlcnNcblx0XHRcdCQoJyNkc2gtZGV0VXNlcnNDdXJyZW50JykudGV4dCgnQ3VycmVudDogJyArIChkYXRhLmdldEludCgndVNvY2tldCcpICsgZGF0YS5nZXRJbnQoJ3VIdHRwJykgKyBkYXRhLmdldEludCgndU5wYycpKSk7XG5cdFx0XHQkKCcjZHNoLWRldFVzZXJzTWF4JykudGV4dCgnTWF4OiAnICsgZGF0YS5nZXRJbnQoJ2NjdU1heCcpKTtcblx0XHRcdCQoJyNkc2gtZGV0VXNlcnNTb2NrZXQnKS50ZXh0KCdTb2NrZXQ6ICcgKyBkYXRhLmdldEludCgndVNvY2tldCcpKTtcblx0XHRcdCQoJyNkc2gtZGV0VXNlcnNIdHRwJykudGV4dCgnSHR0cDogJyArIGRhdGEuZ2V0SW50KCd1SHR0cCcpKTtcblx0XHRcdCQoJyNkc2gtZGV0VXNlcnNOcGMnKS50ZXh0KCdOcGM6ICcgKyBkYXRhLmdldEludCgndU5wYycpKTtcblxuXHRcdFx0Ly8gUm9vbXNcblx0XHRcdCQoJyNkc2gtZGV0Um9vbXMnKS50ZXh0KGRhdGEuZ2V0SW50KCdyVG90YWwnKSk7XG5cdFx0XHQkKCcjZHNoLWRldFJvb21zUmVndWxhcicpLnRleHQoJ1JlZ3VsYXI6ICcgKyAoZGF0YS5nZXRJbnQoJ3JUb3RhbCcpIC0gZGF0YS5nZXRJbnQoJ3JHYW1lJykpKTtcblx0XHRcdCQoJyNkc2gtZGV0Um9vbXNHYW1lJykudGV4dCgnR2FtZTogJyArIGRhdGEuZ2V0SW50KCdyR2FtZScpKTtcblxuXHRcdFx0Ly8gVG90YWwgZGF0YSB0cmFuc2ZlclxuXHRcdFx0JCgnI2RzaC1kZXREYXRhVHJhbnNmZXJPdXQnKS50ZXh0KCdPdXQ6ICcgKyBrQnl0ZXNUb1NpemUoZGF0YS5nZXRMb25nKCdudE91dCcpKSk7XG5cdFx0XHQkKCcjZHNoLWRldERhdGFUcmFuc2ZlckluJykudGV4dCgnSW46ICcgKyBrQnl0ZXNUb1NpemUoZGF0YS5nZXRMb25nKCdudEluJykpKTtcblxuXHRcdFx0Ly8gQ3VycmVudCBkYXRhIHRyYW5zZmVyIHJhdGVcblx0XHRcdGxldCBvYmogPSB0aGlzLl9uZXR3b3JrUlRDaGFydC5nZXRMYXN0RW50cnkoKTtcblxuXHRcdFx0aWYgKG9iaiA9PSBudWxsKVxuXHRcdFx0XHRvYmogPSB7b3V0Z29pbmc6IDAsIGluY29taW5nOiAwfTtcblxuXHRcdFx0JCgnI2RzaC1kZXRUcmFuc2ZlclJhdGVPdXQnKS50ZXh0KCdPdXQ6ICcgKyBrQnl0ZXNUb1NpemUob2JqLm91dGdvaW5nLCAyLCAnS0InLCAnL3MnKSk7XG5cdFx0XHQkKCcjZHNoLWRldFRyYW5zZmVyUmF0ZUluJykudGV4dCgnSW46ICcgKyBrQnl0ZXNUb1NpemUob2JqLmluY29taW5nLCAyLCAnS0InLCAnL3MnKSk7XG5cblx0XHRcdC8vIEF2ZXJhZ2UgZGF0YSB0cmFuc2ZlciByYXRlIG92ZXIgd2hvbGUgdXB0aW1lXG5cdFx0XHRpZiAodGhpcy5fdXB0aW1lU2VjcyA+IDApXG5cdFx0XHR7XG5cdFx0XHRcdGNvbnN0IGF2Z091dCA9IE1hdGgucm91bmQoZGF0YS5nZXRMb25nKCdudE91dCcpIC8gdGhpcy5fdXB0aW1lU2VjcyAqIDEwMCkgLyAxMDA7XG5cdFx0XHRcdGNvbnN0IGF2Z0luID0gTWF0aC5yb3VuZChkYXRhLmdldExvbmcoJ250SW4nKSAvIHRoaXMuX3VwdGltZVNlY3MgKiAxMDApIC8gMTAwO1xuXG5cdFx0XHRcdCQoJyNkc2gtZGV0QXZnVHJhbnNmZXJSYXRlT3V0JykudGV4dCgnT3V0OiAnICsga0J5dGVzVG9TaXplKGF2Z091dCwgMiwgJ0tCJywgJy9zJykpO1xuXHRcdFx0XHQkKCcjZHNoLWRldEF2Z1RyYW5zZmVyUmF0ZUluJykudGV4dCgnSW46ICcgKyBrQnl0ZXNUb1NpemUoYXZnSW4sIDIsICdLQicsICcvcycpKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gRHJvcHBlZCBwYWNrZXRzXG5cdFx0XHRjb25zdCB0b3RhbFBhY2tldHNPdXQgPSBkYXRhLmdldExvbmcoJ3BrdE91dCcpO1xuXG5cdFx0XHRjb25zdCB0b3RhbERyb3BwZWRUY3BQYWNrZXRzT3V0ID0gZGF0YS5nZXRMb25nKCdwa3RPdXREcm9wJyk7XG5cdFx0XHQkKCcjZHNoLWRldERyb3BwZWRUY3BQYWNrZXRzT3V0JykudGV4dChgT3V0IFRDUDogJHt0b3RhbERyb3BwZWRUY3BQYWNrZXRzT3V0fSAoJHtNYXRoLnJvdW5kKHRvdGFsRHJvcHBlZFRjcFBhY2tldHNPdXQgLyB0b3RhbFBhY2tldHNPdXQgKiAxMDApfSUpYCk7XG5cblx0XHRcdGNvbnN0IHRvdGFsRHJvcHBlZFVkcFBhY2tldHNPdXQgPSBkYXRhLmdldExvbmcoJ3BrdE91dFVkcERyb3AnKTtcblx0XHRcdCQoJyNkc2gtZGV0RHJvcHBlZFVkcFBhY2tldHNPdXQnKS50ZXh0KGBPdXQgVURQOiAke3RvdGFsRHJvcHBlZFVkcFBhY2tldHNPdXR9ICgke01hdGgucm91bmQodG90YWxEcm9wcGVkVWRwUGFja2V0c091dCAvIHRvdGFsUGFja2V0c091dCAqIDEwMCl9JSlgKTtcblxuXHRcdFx0Y29uc3QgdG90YWxQYWNrZXRzSW4gPSBkYXRhLmdldExvbmcoJ3BrdEluJyk7XG5cdFx0XHRjb25zdCB0b3RhbERyb3BwZWRQYWNrZXRzSW4gPSBkYXRhLmdldExvbmcoJ3BrdEluRHJvcCcpO1xuXHRcdFx0JCgnI2RzaC1kZXREcm9wcGVkUGFja2V0c0luJykudGV4dChgSW46ICR7dG90YWxEcm9wcGVkUGFja2V0c0lufSAoJHtNYXRoLnJvdW5kKHRvdGFsRHJvcHBlZFBhY2tldHNJbiAvIHRvdGFsUGFja2V0c0luICogMTAwKX0lKWApO1xuXG5cdFx0XHQvLyBTWVNURU0gU1RBVFVTXG5cblx0XHRcdC8vIE91dGdvaW5nIFRDUCBtZXNzYWdlcyBxdWV1ZVxuXHRcdFx0Y29uc3Qgb3V0TXNnUXVldWUgPSBkYXRhLmdldEludCgnb3V0TXNnUXVldWUnKTtcblx0XHRcdGNvbnN0IG91dE1zZ1F1ZXVlTWF4ID0gZGF0YS5nZXRJbnQoJ291dE1zZ1F1ZXVlTWF4Jyk7XG5cdFx0XHR0aGlzLl9vdXRUY3BNc2dRdWV1ZUNoYXJ0LmFkZEVudHJ5KG91dE1zZ1F1ZXVlLCBvdXRNc2dRdWV1ZU1heCk7XG5cdFx0XHR0aGlzLl90Y3BPdXRUaHJlYWRzID0gZGF0YS5nZXRJbnQoJ291dE1zZ1RoJyk7XG5cdFx0XHR0aGlzLl90Y3BPdXRMb2FkID0gdGhpcy5fb3V0VGNwTXNnUXVldWVDaGFydC5sb2FkO1xuXG5cdFx0XHQvLyBPdXRnb2luZyBVRFAgbWVzc2FnZXMgcXVldWVcblx0XHRcdGNvbnN0IG91dFVkcE1zZ1F1ZXVlID0gZGF0YS5nZXRJbnQoJ291dFVkcE1zZ1F1ZXVlJyk7XG5cdFx0XHRjb25zdCBvdXRVZHBNc2dRdWV1ZU1heCA9IGRhdGEuZ2V0SW50KCdvdXRVZHBNc2dRdWV1ZU1heCcpO1xuXHRcdFx0dGhpcy5fb3V0VWRwTXNnUXVldWVDaGFydC5hZGRFbnRyeShvdXRVZHBNc2dRdWV1ZSwgb3V0VWRwTXNnUXVldWVNYXgpO1xuXHRcdFx0dGhpcy5fdWRwT3V0VGhyZWFkcyA9IGRhdGEuZ2V0SW50KCdvdXRVZHBNc2dUaCcpO1xuXHRcdFx0dGhpcy5fdWRwT3V0TG9hZCA9IHRoaXMuX291dFVkcE1zZ1F1ZXVlQ2hhcnQubG9hZDtcblxuXHRcdFx0dGhpcy5fdXBkYXRlT3V0TWVzc2FnZXNRdWV1ZVN0YXR1cygpO1xuXG5cdFx0XHQvLyBTeXN0ZW0gQ29udHJvbGxlciByZXF1ZXN0cyBxdWV1ZVxuXHRcdFx0Y29uc3Qgc3lzQ3RybFF1ZXVlID0gZGF0YS5nZXRJbnQoJ3N5c0N0cmxRdWV1ZScpO1xuXHRcdFx0Y29uc3Qgc3lzQ3RybFF1ZXVlTWF4ID0gZGF0YS5nZXRJbnQoJ3N5c0N0cmxRdWV1ZU1heCcpO1xuXHRcdFx0dGhpcy5fc3lzUXVldWVDaGFydC5hZGRFbnRyeShzeXNDdHJsUXVldWUsIHN5c0N0cmxRdWV1ZU1heCk7XG5cdFx0XHQkKCcjZHNoLXN5c3RlbVF1ZXVlVGhyZWFkcycpLnRleHQodGhpcy5fZ2V0UXVldWVUaHJlYWRzTGFiZWwoZGF0YS5nZXRJbnQoJ3N5c0N0cmxUaCcpKSk7XG5cdFx0XHQkKCcjZHNoLXN5c3RlbVF1ZXVlTG9hZCcpLnRleHQodGhpcy5fZ2V0UXVldWVMb2FkTGFiZWwodGhpcy5fc3lzUXVldWVDaGFydC5sb2FkKSk7XG5cblx0XHRcdC8vIEV4dGVuc2lvbiBDb250cm9sbGVyIHJlcXVlc3RzIHF1ZXVlXG5cdFx0XHRjb25zdCBleHRDdHJsUXVldWUgPSBkYXRhLmdldEludCgnZXh0Q3RybFF1ZXVlJyk7XG5cdFx0XHRjb25zdCBleHRDdHJsUXVldWVNYXggPSBkYXRhLmdldEludCgnZXh0Q3RybFF1ZXVlTWF4Jyk7XG5cdFx0XHR0aGlzLl9leHRRdWV1ZUNoYXJ0LmFkZEVudHJ5KGV4dEN0cmxRdWV1ZSwgZXh0Q3RybFF1ZXVlTWF4KTtcblx0XHRcdCQoJyNkc2gtZXh0ZW5zaW9uUXVldWVUaHJlYWRzJykudGV4dCh0aGlzLl9nZXRRdWV1ZVRocmVhZHNMYWJlbChkYXRhLmdldEludCgnZXh0Q3RybFRoJykpKTtcblx0XHRcdCQoJyNkc2gtZXh0ZW5zaW9uUXVldWVMb2FkJykudGV4dCh0aGlzLl9nZXRRdWV1ZUxvYWRMYWJlbCh0aGlzLl9zeXNRdWV1ZUNoYXJ0LmxvYWQpKTtcblxuXHRcdFx0Ly8gRXZhbHVhdGUgb3ZlcmFsbCBzeXN0ZW0gd29ya2xvYWRcblx0XHRcdGxldCBzeXNXb3JrbG9hZCA9IE1hdGgucm91bmQoKG91dE1zZ1F1ZXVlIC8gb3V0TXNnUXVldWVNYXggK1xuXHRcdFx0XHRcdFx0XHRcdFx0XHQgIG91dFVkcE1zZ1F1ZXVlIC8gb3V0VWRwTXNnUXVldWVNYXggK1xuXHRcdFx0XHQgXHRcdFx0XHRcdFx0ICBzeXNDdHJsUXVldWUgLyBzeXNDdHJsUXVldWVNYXggK1xuXHRcdFx0XHQgXHRcdFx0XHRcdCAgXHQgIGV4dEN0cmxRdWV1ZSAvIGV4dEN0cmxRdWV1ZU1heCkgKiAxMDAgLyA0KTtcblx0XHRcdGlmIChzeXNXb3JrbG9hZCA+IDEwMClcblx0XHRcdFx0c3lzV29ya2xvYWQgPSAxMDA7XG5cblx0XHRcdHRoaXMuX3N5c1dvcmtsb2FkQ2hhcnQuYWRkRW50cnkoc3lzV29ya2xvYWQpO1xuXHRcdH1cblxuXHRcdC8vIFRocmVhZCBkdW1wIHJlY2VpdmVkXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfVEhSRUFEX0RVTVApXG5cdFx0e1xuXHRcdFx0Ly8gRW5hYmxlIGJ1dHRvblxuXHRcdFx0JCgnI2RzaC1kdW1wVGhyZWFkc0J0JykuYXR0cignZGlzYWJsZWQnLCBmYWxzZSk7XG5cblx0XHRcdC8vIFNldCByZXN1bHRcblx0XHRcdCQoJyNkc2gtdGhyZWFkRHVtcFJlc3VsdCcpLnRleHQoZGF0YS5nZXRUZXh0KCdkdW1wJykpO1xuXG5cdFx0XHQvLyBEaXNwbGF5IG1vZGFsXG5cdFx0XHQkKCcjZHNoLXRocmVhZER1bXBNb2RhbCcpLm1vZGFsKCdzaG93Jyk7XG5cdFx0fVxuXHR9XG5cblx0b25VcHRpbWVVcGRhdGVkKHZhbHVlcylcblx0e1xuXHRcdHRoaXMuX3VwdGltZVNlY3MgPSB2YWx1ZXNbM107XG5cdFx0dGhpcy5fdXB0aW1lU2VjcyArPSAodmFsdWVzWzJdICogNjApO1xuXHRcdHRoaXMuX3VwdGltZVNlY3MgKz0gKHZhbHVlc1sxXSAqIDYwICogNjApO1xuXHRcdHRoaXMuX3VwdGltZVNlY3MgKz0gKHZhbHVlc1swXSAqIDI0ICogNjAgKiA2MCk7XG5cblx0XHQkKCcjZHNoLXVwdGltZURheXMnKS50ZXh0KCAodmFsdWVzWzBdIDw9IDkgPyAnMDAnIDogKHZhbHVlc1swXSA8PSA5OSA/ICcwJyA6ICcnKSkgKyB2YWx1ZXNbMF0gKTtcblx0XHQkKCcjZHNoLXVwdGltZUhvdXJzJykudGV4dCggKHZhbHVlc1sxXSA8PSA5ID8gJzAnIDogJycpICsgdmFsdWVzWzFdICk7XG5cdFx0JCgnI2RzaC11cHRpbWVNaW51dGVzJykudGV4dCggKHZhbHVlc1syXSA8PSA5ID8gJzAnIDogJycpICsgdmFsdWVzWzJdICk7XG5cdFx0JCgnI2RzaC11cHRpbWVTZWNvbmRzJykudGV4dCggKHZhbHVlc1szXSA8PSA5ID8gJzAnIDogJycpICsgdmFsdWVzWzNdICk7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBVSSBFVkVOVCBMSVNURU5FUlNcblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRfb25VcGRhdGVJbnRlcnZhbENoYW5nZSgpXG5cdHtcblx0XHQvLyBSZXF1ZXN0IGRhdGEgdG8gc2VydmVyXG5cdFx0dGhpcy5fcmVxdWVzdERhdGEoKTtcblx0fVxuXG5cdF9vblBhdXNlVXBkYXRlQ2xpY2soKVxuXHR7XG5cdFx0dGhpcy5fc2V0Q2hhcnRVcGRhdGVQYXVzZWQodHJ1ZSk7XG5cblx0XHQvLyBIaWRlIHBhdXNlIGJ1dHRvbiBhbmQgc2hvdyBwbGF5IGJ1dHRvblxuXHRcdCQoJyNkc2gtcGF1c2VCdCcpLmFkZENsYXNzKCdoaWRkZW4nKTtcblx0XHQkKCcjZHNoLXBsYXlCdCcpLnJlbW92ZUNsYXNzKCdoaWRkZW4nKTtcblx0fVxuXG5cdF9vblBsYXlVcGRhdGVDbGljaygpXG5cdHtcblx0XHR0aGlzLl9zZXRDaGFydFVwZGF0ZVBhdXNlZChmYWxzZSk7XG5cblx0XHQvLyBIaWRlIHBsYXkgYnV0dG9uIGFuZCBzaG93IHBhdXNlIGJ1dHRvblxuXHRcdCQoJyNkc2gtcGF1c2VCdCcpLnJlbW92ZUNsYXNzKCdoaWRkZW4nKTtcblx0XHQkKCcjZHNoLXBsYXlCdCcpLmFkZENsYXNzKCdoaWRkZW4nKTtcblx0fVxuXG5cdF9vblJlc2V0Q2hhcnRzQ2xpY2soKVxuXHR7XG5cdFx0Ly8gUmVhY3RpdmF0ZSByZWFsdGltZSBjaGFydHMgdXBkYXRlXG5cdFx0dGhpcy5fb25QbGF5VXBkYXRlQ2xpY2soKTtcblxuXHRcdC8vIFJlc2V0IHJlYWx0aW1lIGNoYXJ0c1xuXHRcdHRoaXMuX2NwdVVzYWdlQ2hhcnQucmVzZXQoKTtcblx0XHR0aGlzLl90aHJlYWRDb3VudENoYXJ0LnJlc2V0KCk7XG5cdFx0dGhpcy5fbWVtb3J5Q2hhcnQucmVzZXQoKTtcblx0XHR0aGlzLl9uZXR3b3JrUlRDaGFydC5yZXNldCgpO1xuXHRcdHRoaXMuX3N5c1dvcmtsb2FkQ2hhcnQucmVzZXQoKTtcblx0XHR0aGlzLl9vdXRUY3BNc2dRdWV1ZUNoYXJ0LnJlc2V0KCk7XG5cdFx0dGhpcy5fb3V0VWRwTXNnUXVldWVDaGFydC5yZXNldCgpO1xuXHRcdHRoaXMuX3N5c1F1ZXVlQ2hhcnQucmVzZXQoKTtcblx0XHR0aGlzLl9leHRRdWV1ZUNoYXJ0LnJlc2V0KCk7XG5cdH1cblxuXHRfcmVkcmF3TmV0d29ya0NoYXJ0cygpXG5cdHtcblx0XHQvLyBSZWRyYXcgY2hhcnRzXG5cdFx0dGhpcy5fbmV0d29ya1JUQ2hhcnQucmVkcmF3KCk7XG5cdFx0dGhpcy5fbmV0d29yazI0aENoYXJ0LnJlZHJhdygpO1xuXG5cdFx0Ly8gUmVkcmF3IHRpbWUgcmFuZ2Ugc2xpZGVyXG5cdFx0dGhpcy5fdGltZVNsaWRlci5yZXNpemUoKTtcblx0fVxuXG5cdF9yZWRyYXdPdXRNc2dDaGFydHMoKVxuXHR7XG5cdFx0Ly8gUmVkcmF3IGNoYXJ0c1xuXHRcdHRoaXMuX291dFRjcE1zZ1F1ZXVlQ2hhcnQucmVkcmF3KCk7XG5cdFx0dGhpcy5fb3V0VWRwTXNnUXVldWVDaGFydC5yZWRyYXcoKTtcblxuXHRcdHRoaXMuX3VwZGF0ZU91dE1lc3NhZ2VzUXVldWVTdGF0dXMoKTtcblx0fVxuXG5cdF9vbldpbmRvd1Jlc2l6ZSgpXG5cdHtcblx0XHQvLyBSZWRyYXcgYWxsIGdsb2JhbCBjaGFydHNcblx0XHR0aGlzLl9jcHVVc2FnZUNoYXJ0LnJlZHJhdygpO1xuXHRcdHRoaXMuX3RocmVhZENvdW50Q2hhcnQucmVkcmF3KCk7XG5cdFx0dGhpcy5fbWVtb3J5Q2hhcnQucmVkcmF3KCk7XG5cdFx0dGhpcy5fcmVkcmF3TmV0d29ya0NoYXJ0cygpO1xuXG5cdFx0Ly8gUmVkcmF3IGFsbCBxdWV1ZSBjaGFydHNcblx0XHR0aGlzLl9zeXNXb3JrbG9hZENoYXJ0LnJlZHJhdygpO1xuXHRcdHRoaXMuX3N5c1F1ZXVlQ2hhcnQucmVkcmF3KCk7XG5cdFx0dGhpcy5fZXh0UXVldWVDaGFydC5yZWRyYXcoKTtcblx0XHR0aGlzLl9yZWRyYXdPdXRNc2dDaGFydHMoKTtcblx0fVxuXG5cdF9vblRpbWVSYW5nZUNoYW5nZSgpXG5cdHtcblx0XHRsZXQgdmFsdWVzID0gdGhpcy5fdGltZVNsaWRlci52YWx1ZSgpO1xuXG5cdFx0aWYgKHZhbHVlc1swXSA9PSB2YWx1ZXNbMV0pXG5cdFx0e1xuXHRcdFx0aWYgKHZhbHVlc1sxXSA9PSAtMjQpXG5cdFx0XHRcdHZhbHVlc1sxXSA9IC0yMztcblxuXHRcdFx0dmFsdWVzWzBdID0gdmFsdWVzWzFdIC0gMTtcblxuXHRcdFx0Ly8gUmVzZXQgdGhlIHRpbWUgcmFuZ2Ugc2xpZGVyIHZhbHVlICh3ZSBuZWVkIHRvIHVzZSBzZXRUaW1lb3V0XG5cdFx0XHQvLyBiYWNhdXNlIGRvaW5nIGl0IGluIHRoZSBjaGFuZ2UgZXZlbnQgbGlzdGVuZXIgZG9lc24ndCByZWRyYXcgdGhlIHNsaWRlcilcblx0XHRcdHNldFRpbWVvdXQoJC5wcm94eSggZnVuY3Rpb24odmFsdWVzKSB7IHRoaXMuX3RpbWVTbGlkZXIudmFsdWUodmFsdWVzKTsgfSwgdGhpcyksIDEwLCB2YWx1ZXMpO1xuXHRcdH1cblxuXHRcdHRoaXMuX25ldHdvcmsyNGhDaGFydC5yYW5nZSA9IHZhbHVlcztcblx0fVxuXG5cdF9vblVzZUh0dHBzRm9yV3NNYW5hZ2VyQ2hhbmdlKClcblx0e1xuXHRcdGNvbnN0IHdzTWFuID0gdGhpcy5fd3NNYW5hZ2VyQ29uZmlnO1xuXG5cdFx0bGV0IHVybCA9ICgkKCcjZHNoLXVzZUh0dHBzQ2hlY2snKS5wcm9wKCdjaGVja2VkJykgPyAnaHR0cHMnIDogJ2h0dHAnKSArICc6Ly8nO1xuXHRcdHVybCArPSB0aGlzLnNtYXJ0Rm94LmNvbmZpZy5ob3N0O1xuXHRcdHVybCArPSAnOicgKyAoJCgnI2RzaC11c2VIdHRwc0NoZWNrJykucHJvcCgnY2hlY2tlZCcpID8gd3NNYW4uaHR0cHNQb3J0IDogd3NNYW4uaHR0cFBvcnQpO1xuXHRcdHVybCArPSAnL21hbmFnZXIvc3RhdHVzJztcblxuXHRcdCQoJyNkc2gtdG9Xc01hbmFnZXJCdCcpLmF0dHIoJ2hyZWYnLCB1cmwpO1xuXHR9XG5cblx0X29uRHVtcFRocmVhZHNDbGljaygpXG5cdHtcblx0XHQvLyBEaXNhYmxlIGJ1dHRvblxuXHRcdCQoJyNkc2gtZHVtcFRocmVhZHNCdCcpLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cblx0XHQvLyBTZW5kIHJlcXVlc3QgdG8gZXh0ZW5zaW9uXG5cdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9EVU1QX1RIUkVBRFMpO1xuXHR9XG5cblx0X29uQ29weVRocmVhZER1bXBDbGljaygpXG5cdHtcblx0XHQkKCcjZHNoLXRocmVhZER1bXBSZXN1bHQnKS5hdHRyKCdjb250ZW50ZWRpdGFibGUnLCB0cnVlKTtcblx0XHQkKCcjZHNoLXRocmVhZER1bXBSZXN1bHQnKS5hdHRyKCdzcGVsbGNoZWNrJywgZmFsc2UpO1xuXHRcdCQoJyNkc2gtdGhyZWFkRHVtcFJlc3VsdCcpLmZvY3VzKCk7XG5cdFx0ZG9jdW1lbnQuZXhlY0NvbW1hbmQoJ3NlbGVjdEFsbCcpO1xuXHRcdGRvY3VtZW50LmV4ZWNDb21tYW5kKCdjb3B5Jyk7XG5cdFx0d2luZG93LmdldFNlbGVjdGlvbigpLnJlbW92ZUFsbFJhbmdlcygpO1xuXHRcdCQoJyNkc2gtdGhyZWFkRHVtcFJlc3VsdCcpLmJsdXIoKTtcblx0XHQkKCcjZHNoLXRocmVhZER1bXBSZXN1bHQnKS5hdHRyKCdjb250ZW50ZWRpdGFibGUnLCBmYWxzZSk7XG5cdH1cblxuXHRfb25UaHJlYWREdW1wTW9kYWxIaWRkZW4oKVxuXHR7XG5cdFx0Ly8gQ2xlYXIgbW9kYWwgY29udGVudFxuXHRcdCQoJyNkc2gtdGhyZWFkRHVtcFJlc3VsdCcpLnRleHQoJycpO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8gUFJJVkFURSBNRVRIT0RTXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0X2VuYWJsZVdlYlNlcnZlck1hbmFnZXJBY2Nlc3MoKVxuXHR7XG5cdFx0Y29uc3Qgd3NNYW4gPSB0aGlzLl93c01hbmFnZXJDb25maWc7XG5cblx0XHRpZiAod3NNYW4uaGFzQWNjZXNzICYmICh3c01hbi5odHRwRW5hYmxlZCB8fCB3c01hbi5odHRwc0VuYWJsZWQpKVxuXHRcdHtcblx0XHRcdC8vIEhpZGUgYWxlcnRcblx0XHRcdCQoJyNkc2gtd3NNYW5hZ2VyQWxlcnQnKS5oaWRlKCk7XG5cblx0XHRcdC8vIEVuYWJsZSBidXR0b25cblx0XHRcdCQoJyNkc2gtdG9Xc01hbmFnZXJCdCcpLmF0dHIoJ2Rpc2FibGVkJywgZmFsc2UpO1xuXG5cdFx0XHQvLyBTZXQgY2hlY2tib3hcblx0XHRcdCQoJyNkc2gtdXNlSHR0cHNDaGVjaycpLnByb3AoJ2NoZWNrZWQnLCB3c01hbi5odHRwc0VuYWJsZWQpO1xuXHRcdFx0JCgnI2RzaC11c2VIdHRwc0NoZWNrJykuYXR0cignZGlzYWJsZWQnLCAhd3NNYW4uaHR0cEVuYWJsZWQgfHwgIXdzTWFuLmh0dHBzRW5hYmxlZCk7XG5cblx0XHRcdC8vIEdlbmVyYXRlIGxpbmtcblx0XHRcdHRoaXMuX29uVXNlSHR0cHNGb3JXc01hbmFnZXJDaGFuZ2UoKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdC8vIFNob3cgYWxlcnRcblx0XHRcdCQoJyNkc2gtd3NNYW5hZ2VyQWxlcnQnKS5zaG93KCk7XG5cblx0XHRcdGlmICghd3NNYW4uaGFzQWNjZXNzKVxuXHRcdFx0XHQkKCcjZHNoLXdzTWFuYWdlckFsZXJ0JykuaHRtbCgnQWNjZXNzIHRvIFRvbWNhdCBNYW5hZ2VyIGNvbnNvbGUgcmVxdWlyZXMgYXQgbGVhc3Qgb25lIHVzZXIgdG8gYmUgZGVmaW5lZCBpbiA8ZW0+V2ViIFNlcnZlcjwvZW0+IHRhYiBvZiA8c3Ryb25nPlNlcnZlciBDb25maWd1cmF0b3I8L3N0cm9uZz4gbW9kdWxlLicpO1xuXHRcdFx0ZWxzZVxuXHRcdFx0XHQkKCcjZHNoLXdzTWFuYWdlckFsZXJ0JykuaHRtbCgnQWNjZXNzIHRvIFRvbWNhdCBNYW5hZ2VyIGNvbnNvbGUgcmVxdWlyZXMgZWl0aGVyIEhUVFAgb3IgSFRUUFMgdG8gYmUgZW5hYmxlZCBpbiA8ZW0+V2ViIFNlcnZlcjwvZW0+IHRhYiBvZiA8c3Ryb25nPlNlcnZlciBDb25maWd1cmF0b3I8L3N0cm9uZz4gbW9kdWxlLicpO1xuXG5cdFx0XHQvLyBEaXNhYmxlIGJ1dHRvblxuXHRcdFx0JCgnI2RzaC10b1dzTWFuYWdlckJ0JykuYXR0cignZGlzYWJsZWQnLCB0cnVlKTtcblxuXHRcdFx0Ly8gRGlzYWJsZSBjaGVja2JveFxuXHRcdFx0JCgnI2RzaC11c2VIdHRwc0NoZWNrJykuYXR0cignY2hlY2tlZCcsIHdzTWFuLmh0dHBzRW5hYmxlZCk7XG5cdFx0XHQkKCcjZHNoLXVzZUh0dHBzQ2hlY2snKS5hdHRyKCdkaXNhYmxlZCcsIHRydWUpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBCdWlsZCB0aGUgcG9sbGluZyByZXF1ZXN0IHRvIGJlIHNlbnQgdG8gdGhlIHNlcnZlci5cblx0ICovXG5cdF9yZXF1ZXN0RGF0YShnZXRIaXN0b3J5ID0gZmFsc2UpXG5cdHtcblx0XHQvLyBDbGVhciBwcmV2aW91cyByZXF1ZXN0IHNjaGVkdWxpbmdcblx0XHRjbGVhclRpbWVvdXQodGhpcy5fcmVxdWVzdFRpbWVyKTtcblxuXHRcdC8vIENoZWNrIGlmIGNvbm5lY3Rpb24gaXMgc3RpbGwgYXZhaWxhYmxlXG5cdFx0aWYgKHRoaXMuc21hcnRGb3guaXNDb25uZWN0ZWQpXG5cdFx0e1xuXHRcdFx0Ly8gQnVpbGQgcmVxdWVzdCBwYXJhbWV0ZXJzXG5cdFx0XHRsZXQgcGFyYW1zID0gbmV3IFNGUzJYLlNGU09iamVjdCgpO1xuXG5cdFx0XHRpZiAoZ2V0SGlzdG9yeSlcblx0XHRcdFx0cGFyYW1zLnB1dEJvb2woJ2hpc3RvcnknLCB0cnVlKTtcblxuXHRcdFx0Ly8gU2VuZCByZXF1ZXN0IHRvIGV4dGVuc2lvblxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9HRVRfREFUQSwgcGFyYW1zKTtcblxuXHRcdFx0Ly8gU2NoZWR1bGUgbmV4dCByZXF1ZXN0XG5cdFx0XHR0aGlzLl9yZXF1ZXN0VGltZXIgPSBzZXRUaW1lb3V0KCQucHJveHkodGhpcy5fcmVxdWVzdERhdGEsIHRoaXMpLCBOdW1iZXIodGhpcy5faW50ZXJ2YWxEcm9wRG93bi52YWx1ZSgpKSAqIDEwMDApO1xuXHRcdH1cblx0fVxuXG5cdF9nZXRNZW1PYmplY3QoYnl0ZXMpXG5cdHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0ZGF0YTogYnl0ZXMsXG5cdFx0XHRsYWJlbDogYnl0ZXNUb1NpemUoYnl0ZXMpXG5cdFx0fTtcblx0fVxuXG5cdF9zZXRDaGFydFVwZGF0ZVBhdXNlZChwYXVzZWQpXG5cdHtcblx0XHQvLyBQYXVzZS9yZWFjdGl2YXRlIHJlYWx0aW1lIGNoYXJ0c1xuXHRcdHRoaXMuX2NwdVVzYWdlQ2hhcnQucGF1c2VkID0gcGF1c2VkO1xuXHRcdHRoaXMuX3RocmVhZENvdW50Q2hhcnQucGF1c2VkID0gcGF1c2VkO1xuXHRcdHRoaXMuX21lbW9yeUNoYXJ0LnBhdXNlZCA9IHBhdXNlZDtcblx0XHR0aGlzLl9uZXR3b3JrUlRDaGFydC5wYXVzZWQgPSBwYXVzZWQ7XG5cdFx0dGhpcy5fc3lzV29ya2xvYWRDaGFydC5wYXVzZWQgPSBwYXVzZWQ7XG5cdFx0dGhpcy5fb3V0VGNwTXNnUXVldWVDaGFydC5wYXVzZWQgPSBwYXVzZWQ7XG5cdFx0dGhpcy5fc3lzUXVldWVDaGFydC5wYXVzZWQgPSBwYXVzZWQ7XG5cdFx0dGhpcy5fZXh0UXVldWVDaGFydC5wYXVzZWQgPSBwYXVzZWQ7XG5cdH1cblxuXHRfZ2V0VGhyZWFkc0dyaWREYXRhU291cmNlKGl0ZW1zLCBzb3J0KVxuXHR7XG5cdFx0aWYgKCFpdGVtcylcblx0XHRcdGl0ZW1zID0gJyc7XG5cblx0XHRpZiAoIXNvcnQpXG5cdFx0e1xuXHRcdFx0c29ydCA9IHtcblx0XHRcdFx0ZmllbGQ6ICdjcHVUaW1lJyxcblx0XHRcdFx0ZGlyOiAnZGVzYydcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG5ldyBrZW5kby5kYXRhLkRhdGFTb3VyY2Uoe1xuXHRcdFx0c2NoZW1hOiB7XG5cdFx0XHRcdG1vZGVsOiB7XG5cdFx0XHRcdFx0aWQ6ICdpZCdcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdHNvcnQ6IHNvcnQsXG5cdFx0XHRkYXRhOiBpdGVtc1xuXHRcdH0pO1xuXHR9XG5cblx0X2dldFF1ZXVlVGhyZWFkc0xhYmVsKHRocmVhZHNOdW0pXG5cdHtcblx0XHRyZXR1cm4gYFRocmVhZHM6ICR7dGhyZWFkc051bX1gO1xuXHR9XG5cblx0X2dldFF1ZXVlTG9hZExhYmVsKGxvYWQpXG5cdHtcblx0XHRyZXR1cm4gYEF2Zy4gbWVzc2FnZXM6ICR7bG9hZH1gO1xuXHR9XG5cblx0X3VwZGF0ZU91dE1lc3NhZ2VzUXVldWVTdGF0dXMoKVxuXHR7XG5cdFx0bGV0IHRocmVhZHNTdHIgPSB0aGlzLl9nZXRRdWV1ZVRocmVhZHNMYWJlbCgnLS0nKTtcblx0XHRsZXQgbG9hZFN0ciA9IHRoaXMuX2dldFF1ZXVlTG9hZExhYmVsKCctLScpO1xuXG5cdFx0aWYgKCQoJyNkc2gtdGNwUGlsbCcpLmhhc0NsYXNzKCdhY3RpdmUnKSlcblx0XHR7XG5cdFx0XHR0aHJlYWRzU3RyID0gdGhpcy5fZ2V0UXVldWVUaHJlYWRzTGFiZWwodGhpcy5fdGNwT3V0VGhyZWFkcyk7XG5cdFx0XHRsb2FkU3RyID0gdGhpcy5fZ2V0UXVldWVMb2FkTGFiZWwodGhpcy5fdGNwT3V0TG9hZCk7XG5cdFx0fVxuXG5cdFx0aWYgKCQoJyNkc2gtdWRwUGlsbCcpLmhhc0NsYXNzKCdhY3RpdmUnKSlcblx0XHR7XG5cdFx0XHR0aHJlYWRzU3RyID0gdGhpcy5fZ2V0UXVldWVUaHJlYWRzTGFiZWwodGhpcy5fdWRwT3V0VGhyZWFkcyk7XG5cdFx0XHRsb2FkU3RyID0gdGhpcy5fZ2V0UXVldWVMb2FkTGFiZWwodGhpcy5fdWRwT3V0TG9hZCk7XG5cdFx0fVxuXG5cdFx0JCgnI2RzaC1vdXRnb2luZ01lc3NhZ2VzUXVldWVUaHJlYWRzJykudGV4dCh0aHJlYWRzU3RyKTtcblx0XHQkKCcjZHNoLW91dGdvaW5nTWVzc2FnZXNRdWV1ZUxvYWQnKS50ZXh0KGxvYWRTdHIpO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8gUFJJVkFURSBHRVRURVJTXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQzFIQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzdHQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ3hHQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDM0lBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUNyTkE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUMvSkE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUM1UEE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDclBBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7O0FDekZBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7O0EiLCJzb3VyY2VSb290IjoiIn0=
2094
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtNS5idW5kbGUuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL2NoYXJ0cy9jaGFydC11dGlscy5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL21vZHVsZS1zcGVjaWZpYy9jbHVzdGVyLW1vbml0b3Ivbm9kZS1taW5pLWNoYXJ0cy5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9tb2R1bGVzL2NsdXN0ZXItbW9uaXRvci5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge2J5dGVzVG9TaXplLCBrQnl0ZXNUb1NpemV9IGZyb20gJy4uLy4uL3V0aWxzL3V0aWxpdGllcyc7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRGb3JtYXR0ZWREYXRlVGltZShkYXRlLCBmb3JtYXQgPSAnZGQgTU1NIEhIOm1tOnNzJylcbntcblx0cmV0dXJuIGtlbmRvLnRvU3RyaW5nKGRhdGUsIGZvcm1hdCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRCYXNpY1NoYXJlZFRlbXBsYXRlKHZhbHVlRm9ybWF0ID0gJ3swfScpIHtcblx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHQ8ZGl2IGNsYXNzPVwiY2hhcnQtdG9vbHRpcC1jYXRlZ29yeVwiPjxzdHJvbmc+IzogY2F0ZWdvcnkgIzwvc3Ryb25nPjwvZGl2PlxuXHRcdCMgZm9yICh2YXIgaSA9IDA7IGkgPCBwb2ludHMubGVuZ3RoOyBpKyspIHsgI1xuXHRcdDxkaXY+XG5cdFx0XHQ8aSBjbGFzcz1cImZhcyBmYS1zcXVhcmVcIiBzdHlsZT1cImNvbG9yOiAjOiBwb2ludHNbaV0uY29sb3IgIyBcIj48L2k+XG5cdFx0XHQjOiBwb2ludHNbaV0uc2VyaWVzLm5hbWUjIDogIzoga2VuZG8uZm9ybWF0KCcke3ZhbHVlRm9ybWF0fScsIHBvaW50c1tpXS52YWx1ZSkgI1xuXHRcdDwvZGl2PlxuXHRcdCMgfSAjXG5cdGApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TWVtb3J5U2hhcmVkVGVtcGxhdGUoKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdGRhdGFJdGVtLmJ5dGVzVG9TaXplID0gYnl0ZXNUb1NpemU7IC8vIFBhc3MgYnl0ZXNUb1NpemUgdXRpbGl0eSBmdW5jdGlvbiB0byB0ZW1wbGF0ZVxuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQ8ZGl2IGNsYXNzPVwiY2hhcnQtdG9vbHRpcC1jYXRlZ29yeVwiPjxzdHJvbmc+IzogY2F0ZWdvcnkgIzwvc3Ryb25nPjwvZGl2PlxuXHRcdFx0IyBmb3IgKHZhciBpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykgeyAjXG5cdFx0XHQ8ZGl2PlxuXHRcdFx0XHQ8aSBjbGFzcz1cImZhcyBmYS1zcXVhcmVcIiBzdHlsZT1cImNvbG9yOiAjOiBwb2ludHNbaV0uY29sb3IgIyBcIj48L2k+XG5cdFx0XHRcdCM6IHBvaW50c1tpXS5zZXJpZXMubmFtZSMgOiAjOiBieXRlc1RvU2l6ZShwb2ludHNbaV0udmFsdWUpICNcblx0XHRcdDwvZGl2PlxuXHRcdFx0IyB9ICNcblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRNZW1vcnlWYWx1ZUF4aXNMYWJlbFRlbXBsYXRlKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRkYXRhSXRlbS5ieXRlc1RvU2l6ZSA9IGJ5dGVzVG9TaXplOyAvLyBQYXNzIGJ5dGVzVG9TaXplIHV0aWxpdHkgZnVuY3Rpb24gdG8gdGVtcGxhdGVcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0IzogYnl0ZXNUb1NpemUodmFsdWUpICNcblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXROZXR3b3JrU2hhcmVkVGVtcGxhdGUoY2F0ZWdvcnlGb3JtYXQgPSAnZGQgTU1NIEhIOm1tOnNzJykge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRkYXRhSXRlbS5rQnl0ZXNUb1NpemUgPSBrQnl0ZXNUb1NpemU7IC8vIFBhc3Mga0J5dGVzVG9TaXplIHV0aWxpdHkgZnVuY3Rpb24gdG8gdGVtcGxhdGVcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0PGRpdiBjbGFzcz1cImNoYXJ0LXRvb2x0aXAtY2F0ZWdvcnlcIj48c3Ryb25nPiM6IGtlbmRvLnRvU3RyaW5nKGNhdGVnb3J5LCAnJHtjYXRlZ29yeUZvcm1hdH0nKSAjPC9zdHJvbmc+PC9kaXY+XG5cdFx0XHQjIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7ICNcblx0XHRcdDxkaXY+XG5cdFx0XHRcdDxpIGNsYXNzPVwiZmFzIGZhLXNxdWFyZVwiIHN0eWxlPVwiY29sb3I6ICM6IHBvaW50c1tpXS5jb2xvciAjIFwiPjwvaT5cblx0XHRcdFx0IzogcG9pbnRzW2ldLnNlcmllcy5uYW1lIyA6ICM6IGtCeXRlc1RvU2l6ZShwb2ludHNbaV0udmFsdWUsIDEsICcnLCAnL3MnKSAjXG5cdFx0XHQ8L2Rpdj5cblx0XHRcdCMgfSAjXG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV0d29ya1ZhbHVlQXhpc0xhYmVsVGVtcGxhdGUoKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdGRhdGFJdGVtLmtCeXRlc1RvU2l6ZSA9IGtCeXRlc1RvU2l6ZTsgLy8gUGFzcyBrQnl0ZXNUb1NpemUgdXRpbGl0eSBmdW5jdGlvbiB0byB0ZW1wbGF0ZVxuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQjOiBrQnl0ZXNUb1NpemUodmFsdWUsIDEsICcnLCAnL3MnKSAjXG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV0d29ya1ZhbHVlQXhpc0xhYmVsVGVtcGxhdGVCKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRkYXRhSXRlbS5ieXRlc1RvU2l6ZSA9IGJ5dGVzVG9TaXplOyAvLyBQYXNzIGJ5dGVzVG9TaXplIHV0aWxpdHkgZnVuY3Rpb24gdG8gdGVtcGxhdGVcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0IzogYnl0ZXNUb1NpemUodmFsdWUsIDEsICcnLCAnL3MnKSAjXG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VXNlckNvdW50U2hhcmVkVGVtcGxhdGUoY2F0ZWdvcnlGb3JtYXQgPSAnZGQgTU1NIEhIOm1tOnNzJykge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0PGRpdiBjbGFzcz1cImNoYXJ0LXRvb2x0aXAtY2F0ZWdvcnlcIj48c3Ryb25nPiM6IGtlbmRvLnRvU3RyaW5nKGNhdGVnb3J5LCAnJHtjYXRlZ29yeUZvcm1hdH0nKSAjPC9zdHJvbmc+PC9kaXY+XG5cdFx0XHQjIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7ICNcblx0XHRcdDxkaXY+XG5cdFx0XHRcdDxpIGNsYXNzPVwiZmFzIGZhLXNxdWFyZVwiIHN0eWxlPVwiY29sb3I6ICM6IHBvaW50c1tpXS5jb2xvciAjIFwiPjwvaT5cblx0XHRcdFx0IzogcG9pbnRzW2ldLnNlcmllcy5uYW1lIyA6ICM6IHBvaW50c1tpXS52YWx1ZSAjXG5cdFx0XHQ8L2Rpdj5cblx0XHRcdCMgfSAjXG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VGltZVJhbmdlVG9vbHRpcFRlbXBsYXRlKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRkYXRhSXRlbS5nZXRUb29sdGlwU3RyaW5nID0gZnVuY3Rpb24odjEsIHYyKSB7XG5cdFx0XHRpZiAodjEgPT0gdjIpXG5cdFx0XHR7XG5cdFx0XHRcdGlmICh2MiA9PSAtMjQpXG5cdFx0XHRcdFx0djIgPSAtMjM7XG5cblx0XHRcdFx0djEgPSB2MiAtIDE7XG5cdFx0XHR9XG5cblx0XHRcdGxldCBzdGFydCA9IE1hdGguYWJzKHYxKTtcblx0XHRcdGxldCBlbmQgPSBNYXRoLmFicyh2Mik7XG5cblx0XHRcdHJldHVybiBgRnJvbSAke3N0YXJ0fSBob3VyJHtzdGFydCAhPSAxID8gJ3MnIDogJyd9IGFnbyB0byAke2VuZCA+IDAgPyAoJ3RvICcgKyBlbmQgKyAnIGhvdXInICsgKGVuZCAhPSAxID8gJ3MnIDogJycpICsgJyBhZ28nKSA6ICdub3cnfWA7XG5cdFx0fTsgLy8gUGFzcyB1dGlsaXR5IGZ1bmN0aW9uIHRvIHRlbXBsYXRlXG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdCM6IGdldFRvb2x0aXBTdHJpbmcoc2VsZWN0aW9uU3RhcnQsIHNlbGVjdGlvbkVuZCkgI1xuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFdSQnl0ZXNMYWJlbFRlbXBsYXRlKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0IzogdmFsdWUgIyAjOiBkYXRhSXRlbS51bml0ICNcblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRCYXNpY1RlbXBsYXRlKHZhbHVlRm9ybWF0ID0gJ3swfScpIHtcblx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHQ8ZGl2PlxuXHRcdFx0PHNwYW4gY2xhc3M9XCJ0ZXh0LW5vd3JhcFwiPiM6IGtlbmRvLnRvU3RyaW5nKG5ldyBEYXRlKHZhbHVlLngpLCBcImRkL01NL3l5IEhIOm1tXCIpICM8L3NwYW4+XG5cdFx0XHQ8YnI+XG5cdFx0XHQ8c3Ryb25nIGNsYXNzPVwidGV4dC1ub3dyYXBcIj4jOiBzZXJpZXMubmFtZSAjOiAjOiBrZW5kby5mb3JtYXQoJyR7dmFsdWVGb3JtYXR9JywgdmFsdWUueSkgIyA8L3N0cm9uZz5cblx0XHQ8L2Rpdj5cblx0YCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRNZW1vcnlUZW1wbGF0ZSgpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0ZGF0YUl0ZW0uYnl0ZXNUb1NpemUgPSBieXRlc1RvU2l6ZTsgLy8gUGFzcyBieXRlc1RvU2l6ZSB1dGlsaXR5IGZ1bmN0aW9uIHRvIHRlbXBsYXRlXG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdDxkaXY+XG5cdFx0XHRcdDxzcGFuIGNsYXNzPVwidGV4dC1ub3dyYXBcIj4jOiBrZW5kby50b1N0cmluZyhuZXcgRGF0ZSh2YWx1ZS54KSwgXCJkZC9NTS95eSBISDptbVwiKSAjPC9zcGFuPlxuXHRcdFx0XHQ8YnI+XG5cdFx0XHRcdDxzdHJvbmcgY2xhc3M9XCJ0ZXh0LW5vd3JhcFwiPiM6IHNlcmllcy5uYW1lICM6ICM6IGJ5dGVzVG9TaXplKHZhbHVlLnkpICMgPC9zdHJvbmc+XG5cdFx0XHQ8L2Rpdj5cblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXROZXR3b3JrVGVtcGxhdGUoKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdGRhdGFJdGVtLmJ5dGVzVG9TaXplID0gYnl0ZXNUb1NpemU7IC8vIFBhc3MgYnl0ZXNUb1NpemUgdXRpbGl0eSBmdW5jdGlvbiB0byB0ZW1wbGF0ZVxuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQ8ZGl2PlxuXHRcdFx0XHQ8c3BhbiBjbGFzcz1cInRleHQtbm93cmFwXCI+Izoga2VuZG8udG9TdHJpbmcobmV3IERhdGUodmFsdWUueCksIFwiZGQvTU0veXkgSEg6bW1cIikgIzwvc3Bhbj5cblx0XHRcdFx0PGJyPlxuXHRcdFx0XHQ8c3Ryb25nIGNsYXNzPVwidGV4dC1ub3dyYXBcIj4jOiBzZXJpZXMubmFtZSAjOiAjOiBieXRlc1RvU2l6ZSh2YWx1ZS55LCAxLCAnJywgJy9zJykgIyA8L3N0cm9uZz5cblx0XHRcdDwvZGl2PlxuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cbiIsImltcG9ydCAqIGFzIG1vbWVudCBmcm9tICdtb21lbnQnO1xuaW1wb3J0IHtnZXRCYXNpY1RlbXBsYXRlLCBnZXRNZW1vcnlWYWx1ZUF4aXNMYWJlbFRlbXBsYXRlLCBnZXRNZW1vcnlUZW1wbGF0ZSwgZ2V0TmV0d29ya1RlbXBsYXRlLCBnZXROZXR3b3JrVmFsdWVBeGlzTGFiZWxUZW1wbGF0ZUJ9IGZyb20gJy4uLy4uL2NoYXJ0cy9jaGFydC11dGlscyc7XG5cbmV4cG9ydCBjbGFzcyBOb2RlTWluaUNoYXJ0cyBleHRlbmRzIEhUTUxFbGVtZW50XG57XG5cdGNvbnN0cnVjdG9yKG5vZGVJZCwgbm9kZUFsaWFzLCBub2RlTmFtZSlcblx0e1xuXHQgICAgc3VwZXIoKTtcblxuXHRcdGNvbnN0IHNoYWRvd1Jvb3QgPSB0aGlzLmF0dGFjaFNoYWRvdyh7bW9kZTogJ29wZW4nfSk7XG5cdFx0c2hhZG93Um9vdC5pbm5lckhUTUwgPSBgXG5cdFx0XHQ8bGluayByZWw9XCJzdHlsZXNoZWV0XCIgdHlwZT1cInRleHQvY3NzXCIgaHJlZj1cImFzc2V0cy9jc3MvY3VzdG9tLWJvb3RzdHJhcC5taW4uY3NzXCIgLz5cblx0XHRcdDxsaW5rIHJlbD1cInN0eWxlc2hlZXRcIiB0eXBlPVwidGV4dC9jc3NcIiBocmVmPVwiYXNzZXRzL2Nzcy9rZW5kby5jdXN0b20tYm9vdHN0cmFwLXY0LmNzc1wiIC8+XG5cblx0XHRcdDxzdHlsZT5cblx0XHRcdFx0LmJveCB7XG5cdFx0XHRcdFx0YmFja2dyb3VuZC1jb2xvcjogI0ZGRjtcblx0XHRcdFx0XHRib3JkZXItcmFkaXVzOiAuNXJlbTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC5jaGFydC1jb250YWluZXIge1xuXHRcdFx0XHRcdGN1cnNvcjogcG9pbnRlcjtcblx0XHRcdFx0fVxuXHRcdFx0PC9zdHlsZT5cblxuXHRcdFx0PGRpdiBjbGFzcz1cImNvbnRhaW5lci1mbHVpZFwiPlxuXHRcdFx0XHQ8ZGl2IGNsYXNzPVwicm93IHB5LTMgYm94XCI+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cImNvbC1zbS02IGNvbC1tZC00IGNvbC1sZy0yIGQtZmxleCBmbGV4LWNvbHVtbiBqdXN0aWZ5LWNvbnRlbnQtY2VudGVyXCI+XG5cdFx0XHRcdFx0XHQ8c21hbGwgY2xhc3M9XCJ0ZXh0LW11dGVkXCI+Tm9kZTwvc21hbGw+XG5cdFx0XHRcdFx0XHQ8c3Ryb25nIGlkPVwiYWxpYXNcIj48L3N0cm9uZz5cblx0XHRcdFx0XHRcdDxzbWFsbCBpZD1cIm5hbWVcIj48L3NtYWxsPlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNiBjb2wtbWQtNCBjb2wtbGctMiB0ZXh0LWNlbnRlciBjaGFydC1jb250YWluZXJcIiBkYXRhLXR5cGU9XCJjY3VcIj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjaGFydFwiPjwvZGl2PlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNiBjb2wtbWQtNCBjb2wtbGctMiB0ZXh0LWNlbnRlciBjaGFydC1jb250YWluZXJcIiBkYXRhLXR5cGU9XCJjcHVcIj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjaGFydFwiPjwvZGl2PlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNiBjb2wtbWQtNCBjb2wtbGctMiB0ZXh0LWNlbnRlciBjaGFydC1jb250YWluZXJcIiBkYXRhLXR5cGU9XCJtZW1cIj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjaGFydFwiPjwvZGl2PlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNiBjb2wtbWQtNCBjb2wtbGctMiB0ZXh0LWNlbnRlciBjaGFydC1jb250YWluZXJcIiBkYXRhLXR5cGU9XCJuZXRcIj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjaGFydFwiPjwvZGl2PlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNiBjb2wtbWQtNCBjb2wtbGctMiB0ZXh0LWNlbnRlciBjaGFydC1jb250YWluZXJcIiBkYXRhLXR5cGU9XCJ0aGRcIj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjaGFydFwiPjwvZGl2PlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdDwvZGl2PlxuXHRcdGA7XG5cblx0XHR0aGlzLm5JZCA9IG5vZGVJZDtcblx0XHR0aGlzLm5BbGlhcyA9IG5vZGVBbGlhcztcblx0XHR0aGlzLm5OYW1lID0gbm9kZU5hbWU7XG5cblx0XHQvLyBTZXQgdGFnJ3MgaWQgYXR0cmlidXRlXG5cdFx0dGhpcy5pZCA9ICdub2RlXycgKyBub2RlSWQ7XG5cblx0XHRpZiAobm9kZUFsaWFzKVxuXHRcdHtcblx0XHRcdCQoJyNhbGlhcycsIHNoYWRvd1Jvb3QpLnRleHQobm9kZUFsaWFzKTtcblx0XHRcdCQoJyNuYW1lJywgc2hhZG93Um9vdCkudGV4dChub2RlTmFtZSk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHQkKCcjYWxpYXMnLCBzaGFkb3dSb290KS50ZXh0KG5vZGVOYW1lKTtcblx0XHRcdCQoJyNuYW1lJywgc2hhZG93Um9vdCkuaGlkZSgpO1xuXHRcdH1cblxuXHRcdHRoaXMuX2dldENoYXJ0RGl2KCdjY3UnKS5rZW5kb0NoYXJ0KHtcblx0XHRcdHRyYW5zaXRpb25zOiBmYWxzZSxcblx0XHRcdGNoYXJ0QXJlYToge1xuXHRcdFx0XHRoZWlnaHQ6IDEyMCxcblx0XHRcdFx0YmFja2dyb3VuZDogJ3RyYW5zcGFyZW50Jyxcblx0XHRcdFx0bWFyZ2luOiAwLFxuXHRcdFx0ICAgIHBhZGRpbmc6MFxuXHRcdFx0fSxcblx0ICAgICAgICBsZWdlbmQ6IHtcblx0ICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICB9LFxuXHRcdFx0dGl0bGU6IHtcblx0XHRcdFx0dGV4dDogJ0NvbmN1cnJlbnQgVXNlcnMnLFxuXHRcdFx0XHRmb250OiAnMTJweCBzYW5zLXNlcmlmJyxcblx0XHRcdFx0Y29sb3I6ICcjMjEyNTI5J1xuXHRcdFx0fSxcblx0ICAgICAgICBzZXJpZXNEZWZhdWx0czoge1xuXHQgICAgICAgICAgICB0eXBlOiAnc2NhdHRlckxpbmUnLFxuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlLFxuXHQgICAgICAgICAgICAgICAgZm9ybWF0OiAnezB9Jyxcblx0ICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCdcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWlzc2luZ1ZhbHVlczogJ2dhcCcsXG5cdFx0XHRcdG1hcmtlcnM6IHtcblx0XHRcdCAgICAgIHZpc2libGU6IGZhbHNlLFxuXHRcdFx0XHQgIHR5cGU6ICdjaXJjbGUnLFxuXHRcdFx0XHQgIHNpemU6IDIsXG5cdFx0XHQgICAgfSxcblx0XHRcdFx0d2lkdGg6IDJcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHNlcmllczogW1xuXHRcdFx0XHR7XG5cdCAgICAgICAgICAgICAgICB4RmllbGQ6ICd0cycsXG5cdCAgICAgICAgICAgICAgICB5RmllbGQ6ICd2YWwnLFxuXHRcdFx0XHRcdG5hbWU6ICdDQ1UnLFxuXHRcdFx0XHRcdGNvbG9yOiAnIzMzOTlGRidcblx0ICAgICAgICAgICAgfVxuXHRcdFx0XSxcblx0ICAgICAgICB5QXhpczoge1xuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG5cdFx0XHRcdFx0c3RlcDogMlxuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgICBsaW5lOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaW46IDBcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHhBeGlzOiB7XG5cdFx0XHRcdG1ham9yR3JpZExpbmVzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtYWpvclRpY2tzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fSxcblx0XHRcdFx0bGFiZWxzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fVxuXHQgICAgICAgIH0sXG5cdFx0XHR0b29sdGlwOiB7XG5cdFx0XHRcdHZpc2libGU6IHRydWUsXG5cdFx0XHRcdHRlbXBsYXRlOiBnZXRCYXNpY1RlbXBsYXRlKCd7MH0nKSxcblx0XHRcdFx0YmFja2dyb3VuZDogJyNlNGU0ZTQnXG5cdCAgICAgICAgfVxuXHQgICAgfSkuZGF0YSgna2VuZG9DaGFydCcpO1xuXG5cdFx0dGhpcy5fZ2V0Q2hhcnREaXYoJ2NwdScpLmtlbmRvQ2hhcnQoe1xuXHRcdFx0dHJhbnNpdGlvbnM6IGZhbHNlLFxuXHRcdFx0Y2hhcnRBcmVhOiB7XG5cdFx0XHRcdGhlaWdodDogMTIwLFxuXHRcdFx0XHRiYWNrZ3JvdW5kOiAndHJhbnNwYXJlbnQnLFxuXHRcdFx0XHRtYXJnaW46IDAsXG5cdFx0XHQgICAgcGFkZGluZzowXG5cdFx0XHR9LFxuXHQgICAgICAgIGxlZ2VuZDoge1xuXHQgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgIH0sXG5cdFx0XHR0aXRsZToge1xuXHRcdFx0XHR0ZXh0OiAnQ1BVJyxcblx0XHRcdFx0Zm9udDogJzEycHggc2Fucy1zZXJpZicsXG5cdFx0XHRcdGNvbG9yOiAnIzIxMjUyOSdcblx0XHRcdH0sXG5cdCAgICAgICAgc2VyaWVzRGVmYXVsdHM6IHtcblx0ICAgICAgICAgICAgdHlwZTogJ3NjYXR0ZXJMaW5lJyxcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZSxcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfSUnLFxuXHQgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaXNzaW5nVmFsdWVzOiAnZ2FwJyxcblx0XHRcdFx0bWFya2Vyczoge1xuXHRcdFx0ICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdFx0XHRcdCAgdHlwZTogJ2NpcmNsZScsXG5cdFx0XHRcdCAgc2l6ZTogMyxcblx0XHRcdCAgICB9LFxuXHRcdFx0XHR3aWR0aDogMlxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbXG5cdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgIHhGaWVsZDogJ3RzJyxcblx0ICAgICAgICAgICAgICAgIHlGaWVsZDogJ3ZhbCcsXG5cdFx0XHRcdFx0bmFtZTogJ0NQVScsXG5cdFx0XHRcdFx0Y29sb3I6ICcjMzM5OUZGJ1xuXHQgICAgICAgICAgICB9XG5cdFx0XHRdLFxuXHQgICAgICAgIHlBeGlzOiB7XG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgZm9ybWF0OiAnezB9JSdcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICAgICAgbGluZToge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWluOiAwLFxuXHQgICAgXHRcdG1heDogMTAwLFxuICAgICAgXHRcdFx0bWFqb3JVbml0OiAyNVxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgeEF4aXM6IHtcblx0XHRcdFx0bWFqb3JHcmlkTGluZXM6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1ham9yVGlja3M6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiBmYWxzZVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsYWJlbHM6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiBmYWxzZVxuXHRcdFx0XHR9XG5cdCAgICAgICAgfSxcblx0XHRcdHRvb2x0aXA6IHtcblx0XHRcdFx0dmlzaWJsZTogdHJ1ZSxcblx0XHRcdFx0dGVtcGxhdGU6IGdldEJhc2ljVGVtcGxhdGUoJ3swfSUnKSxcblx0XHRcdFx0YmFja2dyb3VuZDogJyNlNGU0ZTQnLFxuXHQgICAgICAgIH1cblx0ICAgIH0pLmRhdGEoJ2tlbmRvQ2hhcnQnKTtcblxuXHRcdHRoaXMuX2dldENoYXJ0RGl2KCdtZW0nKS5rZW5kb0NoYXJ0KHtcblx0XHRcdHRyYW5zaXRpb25zOiBmYWxzZSxcblx0XHRcdGNoYXJ0QXJlYToge1xuXHRcdFx0XHRoZWlnaHQ6IDEyMCxcblx0XHRcdFx0YmFja2dyb3VuZDogJ3RyYW5zcGFyZW50Jyxcblx0XHRcdFx0bWFyZ2luOiAwLFxuXHRcdFx0ICAgIHBhZGRpbmc6MFxuXHRcdFx0fSxcblx0ICAgICAgICBsZWdlbmQ6IHtcblx0ICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICB9LFxuXHRcdFx0dGl0bGU6IHtcblx0XHRcdFx0dGV4dDogJ01lbW9yeScsXG5cdFx0XHRcdGZvbnQ6ICcxMnB4IHNhbnMtc2VyaWYnLFxuXHRcdFx0XHRjb2xvcjogJyMyMTI1MjknXG5cdFx0XHR9LFxuXHQgICAgICAgIHNlcmllc0RlZmF1bHRzOiB7XG5cdCAgICAgICAgICAgIHR5cGU6ICdzY2F0dGVyTGluZScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nLFxuXHQgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaXNzaW5nVmFsdWVzOiAnZ2FwJyxcblx0XHRcdFx0bWFya2Vyczoge1xuXHRcdFx0ICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdFx0XHRcdCAgdHlwZTogJ2NpcmNsZScsXG5cdFx0XHRcdCAgc2l6ZTogMyxcblx0XHRcdCAgICB9LFxuXHRcdFx0XHR3aWR0aDogMlxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbXG5cdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgIHhGaWVsZDogJ3RzJyxcblx0ICAgICAgICAgICAgICAgIHlGaWVsZDogJ3ZhbCcsXG5cdFx0XHRcdFx0bmFtZTogJ01lbW9yeScsXG5cdFx0XHRcdFx0Y29sb3I6ICcjMzM5OUZGJ1xuXHQgICAgICAgICAgICB9XG5cdFx0XHRdLFxuXHQgICAgICAgIHlBeGlzOiB7XG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgZm9ybWF0OiAnezB9JyxcbiAgICAgIFx0XHRcdFx0dGVtcGxhdGU6IGdldE1lbW9yeVZhbHVlQXhpc0xhYmVsVGVtcGxhdGUoKSxcblx0XHRcdFx0XHRzdGVwOiAyXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICAgIGxpbmU6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1pbjogMCxcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHhBeGlzOiB7XG5cdFx0XHRcdG1ham9yR3JpZExpbmVzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtYWpvclRpY2tzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fSxcblx0XHRcdFx0bGFiZWxzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fVxuXHQgICAgICAgIH0sXG5cdFx0XHR0b29sdGlwOiB7XG5cdFx0XHRcdHZpc2libGU6IHRydWUsXG5cdFx0XHRcdHRlbXBsYXRlOiBnZXRNZW1vcnlUZW1wbGF0ZSgpLFxuXHRcdFx0XHRiYWNrZ3JvdW5kOiAnI2U0ZTRlNCcsXG5cdCAgICAgICAgfVxuXHQgICAgfSkuZGF0YSgna2VuZG9DaGFydCcpO1xuXG5cdFx0dGhpcy5fZ2V0Q2hhcnREaXYoJ3RoZCcpLmtlbmRvQ2hhcnQoe1xuXHRcdFx0dHJhbnNpdGlvbnM6IGZhbHNlLFxuXHRcdFx0Y2hhcnRBcmVhOiB7XG5cdFx0XHRcdGhlaWdodDogMTIwLFxuXHRcdFx0XHRiYWNrZ3JvdW5kOiAndHJhbnNwYXJlbnQnLFxuXHRcdFx0XHRtYXJnaW46IDAsXG5cdFx0XHQgICAgcGFkZGluZzowXG5cdFx0XHR9LFxuXHQgICAgICAgIGxlZ2VuZDoge1xuXHQgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgIH0sXG5cdFx0XHR0aXRsZToge1xuXHRcdFx0XHR0ZXh0OiAnVGhyZWFkcycsXG5cdFx0XHRcdGZvbnQ6ICcxMnB4IHNhbnMtc2VyaWYnLFxuXHRcdFx0XHRjb2xvcjogJyMyMTI1MjknXG5cdFx0XHR9LFxuXHQgICAgICAgIHNlcmllc0RlZmF1bHRzOiB7XG5cdCAgICAgICAgICAgIHR5cGU6ICdzY2F0dGVyTGluZScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nLFxuXHQgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaXNzaW5nVmFsdWVzOiAnZ2FwJyxcblx0XHRcdFx0bWFya2Vyczoge1xuXHRcdFx0ICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdFx0XHRcdCAgdHlwZTogJ2NpcmNsZScsXG5cdFx0XHRcdCAgc2l6ZTogMyxcblx0XHRcdCAgICB9LFxuXHRcdFx0XHR3aWR0aDogMlxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbXG5cdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgIHhGaWVsZDogJ3RzJyxcblx0ICAgICAgICAgICAgICAgIHlGaWVsZDogJ3ZhbCcsXG5cdFx0XHRcdFx0bmFtZTogJ1RocmVhZHMnLFxuXHRcdFx0XHRcdGNvbG9yOiAnIzMzOTlGRidcblx0ICAgICAgICAgICAgfVxuXHRcdFx0XSxcblx0ICAgICAgICB5QXhpczoge1xuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG5cdFx0XHRcdFx0c3RlcDogMlxuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgICBsaW5lOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaW46IDBcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHhBeGlzOiB7XG5cdFx0XHRcdG1ham9yR3JpZExpbmVzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtYWpvclRpY2tzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fSxcblx0XHRcdFx0bGFiZWxzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fVxuXHQgICAgICAgIH0sXG5cdFx0XHR0b29sdGlwOiB7XG5cdFx0XHRcdHZpc2libGU6IHRydWUsXG5cdFx0XHRcdHRlbXBsYXRlOiBnZXRCYXNpY1RlbXBsYXRlKCd7MH0nKSxcblx0XHRcdFx0YmFja2dyb3VuZDogJyNlNGU0ZTQnXG5cdCAgICAgICAgfVxuXHQgICAgfSkuZGF0YSgna2VuZG9DaGFydCcpO1xuXG5cdFx0dGhpcy5fZ2V0Q2hhcnREaXYoJ25ldCcpLmtlbmRvQ2hhcnQoe1xuXHRcdFx0dHJhbnNpdGlvbnM6IGZhbHNlLFxuXHRcdFx0Y2hhcnRBcmVhOiB7XG5cdFx0XHRcdGhlaWdodDogMTIwLFxuXHRcdFx0XHRiYWNrZ3JvdW5kOiAndHJhbnNwYXJlbnQnLFxuXHRcdFx0XHRtYXJnaW46IDAsXG5cdFx0XHQgICAgcGFkZGluZzowXG5cdFx0XHR9LFxuXHQgICAgICAgIGxlZ2VuZDoge1xuXHQgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgIH0sXG5cdFx0XHR0aXRsZToge1xuXHRcdFx0XHR0ZXh0OiAnTmV0d29yaycsXG5cdFx0XHRcdGZvbnQ6ICcxMnB4IHNhbnMtc2VyaWYnLFxuXHRcdFx0XHRjb2xvcjogJyMyMTI1MjknXG5cdFx0XHR9LFxuXHQgICAgICAgIHNlcmllc0RlZmF1bHRzOiB7XG5cdCAgICAgICAgICAgIHR5cGU6ICdzY2F0dGVyTGluZScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nLFxuXHQgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaXNzaW5nVmFsdWVzOiAnZ2FwJyxcblx0XHRcdFx0bWFya2Vyczoge1xuXHRcdFx0ICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdFx0XHRcdCAgdHlwZTogJ2NpcmNsZScsXG5cdFx0XHRcdCAgc2l6ZTogMyxcblx0XHRcdCAgICB9LFxuXHRcdFx0XHR3aWR0aDogMlxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbXG5cdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgIHhGaWVsZDogJ3RzJyxcblx0ICAgICAgICAgICAgICAgIHlGaWVsZDogJ3ZhbCcsXG5cdFx0XHRcdFx0bmFtZTogJ05ldHdvcmsgT3V0Jyxcblx0XHRcdFx0XHRjb2xvcjogJyNDQzAwMDAnLFxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHR7XG5cdCAgICAgICAgICAgICAgICB4RmllbGQ6ICd0cycsXG5cdCAgICAgICAgICAgICAgICB5RmllbGQ6ICd2YWwxJyxcblx0XHRcdFx0XHRuYW1lOiAnTmV0d29yayBJbicsXG5cdFx0XHRcdFx0Y29sb3I6ICcjMDA5OTAwJyxcblx0ICAgICAgICAgICAgfVxuXHRcdFx0XSxcblx0ICAgICAgICB5QXhpczoge1xuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG4gICAgICBcdFx0XHRcdHRlbXBsYXRlOiBnZXROZXR3b3JrVmFsdWVBeGlzTGFiZWxUZW1wbGF0ZUIoKSxcblx0XHRcdFx0XHRzdGVwOiAyXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICAgIGxpbmU6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1pbjogMFxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgeEF4aXM6IHtcblx0XHRcdFx0bWFqb3JHcmlkTGluZXM6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1ham9yVGlja3M6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiBmYWxzZVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsYWJlbHM6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiBmYWxzZVxuXHRcdFx0XHR9XG5cdCAgICAgICAgfSxcblx0XHRcdHRvb2x0aXA6IHtcblx0XHRcdFx0dmlzaWJsZTogdHJ1ZSxcblx0XHRcdFx0dGVtcGxhdGU6IGdldE5ldHdvcmtUZW1wbGF0ZSgpLFxuXHRcdFx0XHRiYWNrZ3JvdW5kOiAnI2U0ZTRlNCdcblx0ICAgICAgICB9XG5cdCAgICB9KS5kYXRhKCdrZW5kb0NoYXJ0Jyk7XG5cblx0XHQvLyBBZGQgY2hhcnQgY29udGFpbmVyIGNsaWNrIGxpc3RlbmVyc1xuXHRcdCQoJy5jaGFydC1jb250YWluZXInLCB0aGlzLnNoYWRvd1Jvb3QpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25DaGFydENvbnRhaW5lckNsaWNrLCB0aGlzKSk7XG5cblx0XHQkKHdpbmRvdykub24oJ3Jlc2l6ZScsICQucHJveHkodGhpcy5fb25XaW5kb3dSZXNpemUsIHRoaXMpKTtcblx0XHR0aGlzLl9vbldpbmRvd1Jlc2l6ZSgpO1xuXHR9XG5cblx0X29uV2luZG93UmVzaXplKClcblx0e1xuXHRcdHRoaXMuX2dldENoYXJ0V2lkZ2V0KCdjY3UnKS5yZWRyYXcoKTtcblx0XHR0aGlzLl9nZXRDaGFydFdpZGdldCgnY3B1JykucmVkcmF3KCk7XG5cdFx0dGhpcy5fZ2V0Q2hhcnRXaWRnZXQoJ21lbScpLnJlZHJhdygpO1xuXHRcdHRoaXMuX2dldENoYXJ0V2lkZ2V0KCd0aGQnKS5yZWRyYXcoKTtcblx0XHR0aGlzLl9nZXRDaGFydFdpZGdldCgnbmV0JykucmVkcmF3KCk7XG5cdH1cblxuXHRkZXN0cm95KClcblx0e1xuXHRcdCQod2luZG93KS5vZmYoJ3Jlc2l6ZScpO1xuXHR9XG5cblx0YWRkQ2hhcnRFbnRyaWVzKHR5cGUsIGRhdGEsIGRhdGExLCBpbnRlcnZhbE1pbGxpcylcblx0e1xuXHRcdGxldCBsYXN0VGltZXN0YW1wID0gZGF0YS5nZXRMb25nKCdsYXN0Jyk7XG5cdFx0bGV0IHZhbHVlcyA9IGRhdGEuZ2V0TG9uZ0FycmF5KCdkYXRhJyk7XG5cdFx0bGV0IHZhbHVlczEgPSAoZGF0YTEgIT0gbnVsbCA/IGRhdGExLmdldExvbmdBcnJheSgnZGF0YScpIDogbnVsbCk7XG5cdFx0bGV0IGNoYXJ0V2lkZ2V0ID0gdGhpcy5fZ2V0Q2hhcnRXaWRnZXQodHlwZSk7XG5cblx0XHR0aGlzLl9hZGRDaGFydEVudHJpZXMoY2hhcnRXaWRnZXQsIHZhbHVlcywgdmFsdWVzMSwgaW50ZXJ2YWxNaWxsaXMsIGxhc3RUaW1lc3RhbXApO1xuXHR9XG5cblx0X2FkZENoYXJ0RW50cmllcyhjaGFydFdpZGdldCwgdmFsdWVzLCB2YWx1ZXMxLCBpbnRlcnZhbE1pbGxpcywgbGFzdFRpbWVzdGFtcClcblx0e1xuXHRcdC8vIERpdmlkZSBpbnRlcnZhbCBieSB0aGUgbnVtYmVyIG9mIGRhdGEgcG9pbnRzIHRvIGNhbGN1bGF0ZSB0aGVpciB0aW1lc3RhbXBzXG5cdFx0bGV0IHNsaWNlTWlsbGlzID0gTWF0aC5yb3VuZChpbnRlcnZhbE1pbGxpcyAvIHZhbHVlcy5sZW5ndGgpO1xuXG5cdFx0bGV0IGRzID0gbmV3IGtlbmRvLmRhdGEuRGF0YVNvdXJjZSgpO1xuXHRcdGxldCBmaXJzdFRpbWVzdGFtcCA9IGxhc3RUaW1lc3RhbXAgLSBpbnRlcnZhbE1pbGxpcztcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdmFsdWVzLmxlbmd0aDsgaSsrKVxuXHRcdHtcblx0XHRcdGxldCB0aW1lc3RhbXAgPSBmaXJzdFRpbWVzdGFtcCArIChzbGljZU1pbGxpcyAqIGkpO1xuXG5cdFx0XHRsZXQgdmFsdWUgPSB2YWx1ZXNbaV0gPCAwID8gbnVsbCA6IHZhbHVlc1tpXTtcblx0XHRcdGxldCB2YWx1ZTEgPSB2YWx1ZXMxID8gKHZhbHVlczFbaV0gPCAwID8gbnVsbCA6IHZhbHVlczFbaV0pIDogbnVsbDtcblxuXHRcdFx0bGV0IGVudHJ5ID0ge1xuXHRcdFx0XHR0czogdGltZXN0YW1wLFxuXHRcdFx0XHR2YWw6IHZhbHVlLFxuXHRcdFx0XHR2YWwxOiB2YWx1ZTEsXG5cdFx0XHR9O1xuXG5cdFx0XHRkcy5hZGQoZW50cnkpO1xuXHRcdH1cblxuXHRcdC8vIFNldCBjaGFydCdzIHgtYXhpcyBsaW1pdHNcblx0XHRjaGFydFdpZGdldC5vcHRpb25zLnhBeGlzLm1pbiA9IGZpcnN0VGltZXN0YW1wO1xuXHRcdGNoYXJ0V2lkZ2V0Lm9wdGlvbnMueEF4aXMubWF4ID0gbGFzdFRpbWVzdGFtcDtcblxuXHRcdGNoYXJ0V2lkZ2V0LnNldERhdGFTb3VyY2UoZHMpO1xuXHR9XG5cblx0X2dldENoYXJ0RGl2KHR5cGUpXG5cdHtcblx0XHRyZXR1cm4gJCgnLmNoYXJ0LWNvbnRhaW5lcltkYXRhLXR5cGU9XCInICsgdHlwZSArICdcIl0gLmNoYXJ0JywgdGhpcy5zaGFkb3dSb290KTtcblx0fVxuXG5cdF9nZXRDaGFydFdpZGdldCh0eXBlKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2dldENoYXJ0RGl2KHR5cGUpLmRhdGEoJ2tlbmRvQ2hhcnQnKTtcblx0fVxuXG5cdF9vbkNoYXJ0Q29udGFpbmVyQ2xpY2soZSlcblx0e1xuXHRcdGxldCBjaGFydFR5cGUgPSAkKGUuY3VycmVudFRhcmdldCkuZGF0YSgndHlwZScpO1xuXG5cdFx0Ly8gRGlzcGF0Y2ggY3VzdG9tIGV2ZW50XG5cdFx0bGV0IGV2dCA9IG5ldyBDdXN0b21FdmVudCgnY2hhcnRDbGljaycsIHtcblx0ICAgIFx0ZGV0YWlsOiB7XG5cdFx0XHRcdHR5cGU6IGNoYXJ0VHlwZSxcblx0XHRcdFx0bm9kZTogdGhpcy5uSWQsXG5cdFx0XHRcdG9wdGlvbnM6IHRoaXMuX2dldENoYXJ0V2lkZ2V0KGNoYXJ0VHlwZSkub3B0aW9uc1xuXHRcdFx0fSxcblx0XHRcdGJ1YmJsZXM6IHRydWUsXG5cdFx0XHRjYW5jZWxhYmxlOiBmYWxzZSxcblx0XHRcdGNvbXBvc2VkOiB0cnVlIC8vIEFsbG93cyBldmVudCB0byBidWJibGUgb3V0c2lkZSBvZiBDdXN0b20gRWxlbWVudFxuXHRcdH0pO1xuXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KGV2dCk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdub2RlLW1pbmktY2hhcnRzJykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ25vZGUtbWluaS1jaGFydHMnLCBOb2RlTWluaUNoYXJ0cyk7XG4iLCJpbXBvcnQge0Jhc2VNb2R1bGV9IGZyb20gJy4vYmFzZS1tb2R1bGUnO1xuaW1wb3J0ICogYXMgbW9tZW50IGZyb20gJ21vbWVudCc7XG5pbXBvcnQge2J5dGVzVG9TaXplLCByb3VuZFRvRGVjaW1hbHN9IGZyb20gJy4uL3V0aWxzL3V0aWxpdGllcyc7XG5pbXBvcnQge05vZGVNaW5pQ2hhcnRzfSBmcm9tICcuLi9jb21wb25lbnRzL21vZHVsZS1zcGVjaWZpYy9jbHVzdGVyLW1vbml0b3Ivbm9kZS1taW5pLWNoYXJ0cyc7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIENsdXN0ZXJNb25pdG9yIGV4dGVuZHMgQmFzZU1vZHVsZVxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKCdjbHVzdGVyTW9uJyk7XG5cblx0XHR0aGlzLk1BWF9MT0dfU0laRSA9IDEwMDtcblxuXHRcdC8vIE91dGdvaW5nIHJlcXVlc3RzXG5cdFx0dGhpcy5SRVFfR0VUX05PREVTID0gJ2dldE5vZGVzJztcblx0XHR0aGlzLlJFUV9ERUFDVElWQVRFX05PREVTID0gJ2RlYWN0Jztcblx0XHR0aGlzLlJFUV9HRVRfTk9ERVNfREFUQSA9ICdnZXREYXRhTic7XG5cdFx0dGhpcy5SRVFfR0VUX0NIQVJUX0RBVEEgPSAnZ2V0RGF0YUMnO1xuXHRcdHRoaXMuUkVRX1NDQUxFX1VQID0gJ3NjYWxlVXAnO1xuXHRcdHRoaXMuUkVRX0dFVF9MT0dfTUVTU0FHRVMgPSAnZ2V0TG9nJztcblxuXHRcdC8vIEluY29taW5nIHJlc3BvbnNlc1xuXHRcdHRoaXMuUkVTUF9OT0RFUyA9ICdub2Rlcyc7XG5cdFx0dGhpcy5SRVNQX05PREVTX0RBVEEgPSAnZGF0YU4nO1xuXHRcdHRoaXMuUkVTUF9DSEFSVF9EQVRBID0gJ2RhdGFDJztcblx0XHR0aGlzLlJFU1BfTE9HX01FU1NBR0VTID0gJ2xvZyc7XG5cblx0XHR0aGlzLmludGVydmFscyA9IFtcblx0XHRcdHtcblx0XHRcdFx0bGFiZWw6ICdMYXN0IGhvdXInLFxuXHRcdFx0XHRtaW51dGVzOiA2MCxcblx0XHRcdFx0cG9pbnRzMTogMzAsXG5cdFx0XHRcdHBvaW50czI6IDMwLFxuXHRcdFx0fSxcblx0XHRcdHtcblx0XHRcdFx0bGFiZWw6ICdMYXN0IDMgaG91cnMnLFxuXHRcdFx0XHRtaW51dGVzOiAxODAsXG5cdFx0XHRcdHBvaW50czE6IDMwLFxuXHRcdFx0XHRwb2ludHMyOiA5MCxcblx0XHRcdH0sXG5cdFx0XHR7XG5cdFx0XHRcdGxhYmVsOiAnTGFzdCAxMiBob3VycycsXG5cdFx0XHRcdG1pbnV0ZXM6IDcyMCxcblx0XHRcdFx0cG9pbnRzMTogMzAsXG5cdFx0XHRcdHBvaW50czI6IDE4MCxcblx0XHRcdH0sXG5cdFx0XHR7XG5cdFx0XHRcdGxhYmVsOiAnTGFzdCAyNCBob3VycycsXG5cdFx0XHRcdG1pbnV0ZXM6IDE0NDAsXG5cdFx0XHRcdHBvaW50czE6IDMwLFxuXHRcdFx0XHRwb2ludHMyOiAzNjAsXG5cdFx0XHR9LFxuXHRcdF1cblxuXHRcdHRoaXMuX3NlbGVjdGVkTm9kZXMgPSBbXTtcblx0XHR0aGlzLl9zZWxlY3RlZEFjdGl2ZU5vZGVzID0gW107XG5cdFx0dGhpcy5fY2hhcnRlZE5vZGVzID0gW107XG5cdFx0dGhpcy5fY2hhcnRJbmZvID0gbnVsbDtcblx0XHR0aGlzLl9sYXN0TG9nc1JlcVRpbWVzdGFtcCA9IDA7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBDT01NT04gTU9EVUxFIElOVEVSRkFDRSBNRVRIT0RTXG5cdC8vIFRoaXMgbWVtYmVycyBhcmUgdXNlZCBieSB0aGUgbWFpbiBjb250cm9sbGVyXG5cdC8vIHRvIGNvbW11bmljYXRlIHdpdGggdGhlIG1vZHVsZSdzIGNvbnRyb2xsZXIuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0aW5pdGlhbGl6ZShpZERhdGEsIHNoZWxsQ29udHJvbGxlcilcblx0e1xuXHRcdC8vIENhbGwgc3VwZXIgbWV0aG9kXG5cdFx0c3VwZXIuaW5pdGlhbGl6ZShpZERhdGEsIHNoZWxsQ29udHJvbGxlcik7XG5cblx0XHQvLyBJbml0aWFsaXplIHNjcm9sbGluZyB0YWJzXG5cdFx0JCgnI2NsbS10YWJOYXZpZ2F0b3IgPiAjdGFicycpLnNjcm9sbGluZ1RhYnMoe1xuXHRcdFx0Ym9vdHN0cmFwVmVyc2lvbjogNCxcblx0XHRcdHNjcm9sbFRvVGFiRWRnZTogdHJ1ZSxcblx0XHRcdGVuYWJsZVN3aXBpbmc6IHRydWUsXG5cdFx0XHRkaXNhYmxlU2Nyb2xsQXJyb3dzT25GdWxseVNjcm9sbGVkOiB0cnVlLFxuXHRcdFx0Y3NzQ2xhc3NMZWZ0QXJyb3c6ICdmYSBmYS1jaGV2cm9uLWxlZnQnLFxuXHRcdFx0Y3NzQ2xhc3NSaWdodEFycm93OiAnZmEgZmEtY2hldnJvbi1yaWdodCdcblx0XHR9KTtcblxuXHRcdC8vIEluaXRpYWxpemUgYnV0dG9uc1xuXHRcdCQoJyNjbG0tZGVhY3RpdmF0ZUJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbkRlYWN0aXZhdGVCdENsaWNrLCB0aGlzKSk7XG5cdFx0JCgnI2NsbS1zY2FsZVVwQnQnKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uU2NhbGVVcEJ0Q2xpY2ssIHRoaXMpKTtcblx0XHQkKCcjY2xtLXNjYWxlVXBNb2RhbEJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vblNjYWxlVXBDb25maXJtQnRDbGljaywgdGhpcykpO1xuXHRcdCQoJyNjbG0tcmVmcmVzaEJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9yZXF1ZXN0Tm9kZXNMaXN0LCB0aGlzKSk7XG5cblx0XHQvLyBJbml0aWFsaXplIGdyaWRcblx0XHR0aGlzLl9ncmlkID0gJCgnI2NsbS1ub2Rlc0xpc3QnKS5rZW5kb0dyaWQoe1xuXHRcdFx0c2Nyb2xsYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgIHNvcnRhYmxlOiB0cnVlLFxuXHRcdFx0Ly9yZXNpemFibGU6IHRydWUsXG5cdFx0XHRzZWxlY3RhYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIGNvbHVtbnM6IFtcblx0XHRcdFx0e1xuXHRcdFx0XHRcdHNlbGVjdGFibGU6IHRydWUsXG5cdFx0XHRcdFx0d2lkdGg6IDQxXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgIGZpZWxkOiAnbmFtZScsXG5cdCAgICAgICAgICAgICAgICB3aWR0aDogMjUwLFxuXHRcdFx0XHRcdHRpdGxlOiAnTm9kZScsXG5cdFx0XHRcdFx0dGVtcGxhdGU6IGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0XHRcdFx0XHRpZiAoZGF0YUl0ZW1bJ2FsaWFzJ10pXG5cdFx0XHRcdFx0XHRcdHJldHVybiAnPGRpdiBjbGFzcz1cIm5hbWUtY2VsbFwiPjxzcGFuPicgKyBkYXRhSXRlbVsnYWxpYXMnXSArICc8L3NwYW4+IDxhIGhyZWY9XCJodHRwOi8vJyArIGRhdGFJdGVtWyduYW1lJ10gKyAnOjgwODAvYWRtaW5cIiBjbGFzcz1cIm5hbWUtYWRtaW4tbGlua1wiIHRhcmdldD1cIl9ibGFua1wiPjxpIGNsYXNzPVwiZmFzIGZhLXRvb2xib3hcIj48L2k+PC9hPjxicj48c21hbGwgY2xhc3M9XCJ0ZXh0LW11dGVkXCI+JyArIGRhdGFJdGVtWyduYW1lJ10gKyAnPHNtYWxsPjwvZGl2Pic7XG5cdFx0XHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0XHRcdHJldHVybiAnPGRpdiBjbGFzcz1cIm5hbWUtY2VsbFwiPjxzcGFuPicgKyBkYXRhSXRlbVsnbmFtZSddICsgJzwvc3Bhbj4gPGEgaHJlZj1cImh0dHA6Ly8nICsgZGF0YUl0ZW1bJ25hbWUnXSArICc6ODA4MC9hZG1pblwiIGNsYXNzPVwibmFtZS1hZG1pbi1saW5rXCIgdGFyZ2V0PVwiX2JsYW5rXCI+PGkgY2xhc3M9XCJmYXMgZmEtdG9vbGJveFwiPjwvaT48L2E+PC9kaXY+Jztcblx0XHRcdFx0XHR9XG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICAgIHtcblx0ICAgICAgICAgICAgICAgIGZpZWxkOiAnY2N1Jyxcblx0ICAgICAgICAgICAgICAgIHdpZHRoOiA4MCxcblx0ICAgICAgICAgICAgICAgIHRpdGxlOiAnQ0NVJyxcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICAgICAge1xuXHQgICAgICAgICAgICAgICAgZmllbGQ6ICdjcHUnLFxuXHQgICAgICAgICAgICAgICAgd2lkdGg6IDgwLFxuXHQgICAgICAgICAgICAgICAgdGl0bGU6ICdDUFUnLFxuXHRcdFx0XHRcdHRlbXBsYXRlOiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHJvdW5kVG9EZWNpbWFscyhkYXRhSXRlbVsnY3B1J10sIDIpICsgJyUnO1xuXHRcdFx0XHRcdH1cblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0e1xuICAgICAgICAgICAgICAgICAgICB0aXRsZTogJ01lbW9yeScsXG4gICAgICAgICAgICAgICAgICAgIGNvbHVtbnM6IFtcblx0XHRcdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgZmllbGQ6ICd1c2VkTWVtJyxcblx0ICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg6IDEwMCxcblx0XHRcdFx0XHRcdFx0dGl0bGU6ICdVc2VkJyxcblx0XHRcdFx0XHRcdFx0dGVtcGxhdGU6IGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGJ5dGVzVG9TaXplKGRhdGFJdGVtWyd1c2VkTWVtJ10pO1xuXHRcdFx0XHRcdFx0XHR9XG5cdCAgICAgICAgICAgICAgICAgICAgfSxcblx0XHRcdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgZmllbGQ6ICdhbGxvY01lbScsXG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoOiAxMDAsXG5cdFx0XHRcdFx0XHRcdHRpdGxlOiAnQWxsb2NhdGVkJyxcblx0XHRcdFx0XHRcdFx0dGVtcGxhdGU6IGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGJ5dGVzVG9TaXplKGRhdGFJdGVtWydhbGxvY01lbSddKTtcblx0XHRcdFx0XHRcdFx0fVxuICAgICAgICAgICAgICAgICAgICBcdH1cblx0XHRcdFx0XHRdXG4gICAgICAgICAgICAgICAgfSxcblx0XHRcdFx0e1xuICAgICAgICAgICAgICAgICAgICB0aXRsZTogJ05ldHdvcmsnLFxuICAgICAgICAgICAgICAgICAgICBjb2x1bW5zOiBbXG5cdFx0XHRcdFx0XHR7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIGZpZWxkOiAnbmV0SW4nLFxuXHQgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aDogMTAwLFxuXHRcdFx0XHRcdFx0XHR0aXRsZTogJ0luJyxcblx0XHRcdFx0XHRcdFx0dGVtcGxhdGU6IGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIChkYXRhSXRlbVsnbmV0SW4nXSA+IC0xID8gYnl0ZXNUb1NpemUoZGF0YUl0ZW1bJ25ldEluJ10sIDIsICdLQicsICcvcycpIDogJyZuZGFzaDsnKTtcblx0XHRcdFx0XHRcdFx0fVxuXHQgICAgICAgICAgICAgICAgICAgIH0sXG5cdFx0XHRcdFx0XHR7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIGZpZWxkOiAnbmV0T3V0Jyxcblx0ICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg6IDEwMCxcblx0XHRcdFx0XHRcdFx0dGl0bGU6ICdPdXQnLFxuXHRcdFx0XHRcdFx0XHR0ZW1wbGF0ZTogZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gKGRhdGFJdGVtWyduZXRPdXQnXSA+IC0xID8gYnl0ZXNUb1NpemUoZGF0YUl0ZW1bJ25ldE91dCddLCAyLCAnS0InLCAnL3MnKSA6ICcmbmRhc2g7Jyk7XG5cdFx0XHRcdFx0XHRcdH1cbiAgICAgICAgICAgICAgICAgICAgXHR9XG5cdFx0XHRcdFx0XVxuICAgICAgICAgICAgICAgIH0sXG5cdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgIGZpZWxkOiAndGhyZWFkcycsXG5cdCAgICAgICAgICAgICAgICB3aWR0aDogMTAwLFxuXHRcdFx0XHRcdHRpdGxlOiAnVGhyZWFkcycsXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgIGZpZWxkOiAncm9vbXMnLFxuXHQgICAgICAgICAgICAgICAgd2lkdGg6IDEwMCxcblx0XHRcdFx0XHR0aXRsZTogJ1Jvb21zJyxcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0e1xuXHQgICAgICAgICAgICAgICAgZmllbGQ6ICdqb2luVGltZScsXG5cdCAgICAgICAgICAgICAgICB3aWR0aDogMTAwLFxuXHRcdFx0XHRcdHRpdGxlOiAnSm9pbmVkJyxcblx0XHRcdFx0XHRzb3J0YWJsZTogZmFsc2UsXG5cdFx0XHRcdFx0dGVtcGxhdGU6ICQucHJveHkodGhpcy5fZ2V0VGltZVNpbmNlSm9pblRlbXBsYXRlLCB0aGlzKVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHR7XG5cdCAgICAgICAgICAgICAgICBmaWVsZDogJ2hlYWx0aCcsXG5cdCAgICAgICAgICAgICAgICB3aWR0aDogNzUsXG5cdFx0XHRcdFx0dGl0bGU6ICdIZWFsdGgnLFxuXHRcdFx0XHRcdHNvcnRhYmxlOiBmYWxzZSxcblx0XHRcdFx0XHR0ZW1wbGF0ZTogJC5wcm94eSh0aGlzLl9nZXRIZWFsdGhUZW1wbGF0ZSwgdGhpcylcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0e1xuXHQgICAgICAgICAgICAgICAgZmllbGQ6ICdyZWN5Y2xhYmxlJyxcblx0ICAgICAgICAgICAgICAgIHdpZHRoOiA0NSxcblx0XHRcdFx0XHR0aXRsZTogJ1IuJyxcblx0XHRcdFx0XHRzb3J0YWJsZTogZmFsc2UsXG5cdFx0XHRcdFx0dGVtcGxhdGU6ICQucHJveHkodGhpcy5fZ2V0UmVjeWNsYWJsZVRlbXBsYXRlLCB0aGlzKVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHR7XG5cdCAgICAgICAgICAgICAgICBmaWVsZDogJ3Rlcm1pbmFibGUnLFxuXHQgICAgICAgICAgICAgICAgd2lkdGg6IDQ1LFxuXHRcdFx0XHRcdHRpdGxlOiAnVC4nLFxuXHRcdFx0XHRcdHNvcnRhYmxlOiBmYWxzZSxcblx0XHRcdFx0XHR0ZW1wbGF0ZTogJC5wcm94eSh0aGlzLl9nZXRUZXJtaW5hYmxlVGVtcGxhdGUsIHRoaXMpXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRdLFxuXHRcdFx0bm9SZWNvcmRzOiB7XG5cdFx0XHRcdHRlbXBsYXRlOiAnTm8gZ2FtZSBub2Rlcy4nXG5cdFx0XHR9LFxuXHRcdFx0ZGF0YVNvdXJjZToge1xuXHRcdFx0XHRzY2hlbWE6IHtcblx0XHRcdFx0XHRtb2RlbDoge1xuXHRcdFx0XHRcdFx0aWQ6ICdpZCcsXG5cdFx0XHRcdFx0XHQvLyBmaWVsZHM6IHtcblx0XHRcdFx0XHRcdC8vIFx0aWQ6IHsgdHlwZTogJ3N0cmluZycgfSxcblx0XHRcdFx0XHRcdC8vIFx0YWN0aXZlOiB7IHR5cGU6ICdib29sZWFuJyB9XG5cdFx0XHRcdFx0XHQvLyB9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRncm91cDoge1xuXHRcdFx0XHRcdGZpZWxkOiAnYWN0aXZlJyxcblx0XHRcdFx0XHRkaXI6ICdkZXNjJyxcblx0XHRcdFx0fVxuICAgICAgICAgICAgfSxcblx0XHRcdGNoYW5nZTogJC5wcm94eSh0aGlzLl9vbk5vZGVzR3JpZENoYW5nZSwgdGhpcyksXG5cdFx0XHRkYXRhQm91bmQ6ICQucHJveHkodGhpcy5fb25Ob2Rlc0dyaWREYXRhQm91bmQsIHRoaXMpLFxuICAgICAgICB9KS5kYXRhKCdrZW5kb0dyaWQnKTtcblxuXHRcdC8vIEFkZCBsaXN0ZW5lciB0byBtaW5pIGNoYXJ0cyBjb250YWluZXJcblx0XHQkKCcjY2xtLW5vZGVNaW5pQ2hhcnRzQ29udGFpbmVyJykub24oJ2NoYXJ0Q2xpY2snLCAkLnByb3h5KHRoaXMuX29uTWluaUNoYXJ0Q2xpY2ssIHRoaXMpKTtcblxuXHRcdC8vIENvbmZpZ3VyZSBkZXRhaWwgY2hhcnQgbW9kYWxcblx0XHQkKCcjY2xtLWNoYXJ0TW9kYWwnKS5tb2RhbCh7XG5cdFx0XHRiYWNrZHJvcDogJ3N0YXRpYycsXG5cdFx0XHRrZXlib2FyZDogZmFsc2UsXG5cdFx0XHRzaG93OiBmYWxzZSxcblx0XHR9KTtcblxuXHRcdC8vIEFkZCBldmVudCBsaXN0ZW5lciBmb3IgbW9kYWwgaGlkZGVuIGV2ZW50XG5cdFx0JCgnI2NsbS1jaGFydE1vZGFsJykub24oJ2hpZGRlbi5icy5tb2RhbCcsICQucHJveHkodGhpcy5fb25DaGFydE1vZGFsSGlkZGVuLCB0aGlzKSk7XG5cblx0XHQvLyBJbml0aWFsaXplIGRhdGEgaW50ZXJ2YWwgZHJvcGRvd25zXG5cdFx0bGV0IGl0ZW1zID0gW107XG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmludGVydmFscy5sZW5ndGg7IGkrKylcblx0XHRcdGl0ZW1zLnB1c2goe2xhYmVsOnRoaXMuaW50ZXJ2YWxzW2ldLmxhYmVsLCB2YWx1ZTppfSk7XG5cblx0XHR0aGlzLl9tYWluUmFuZ2VERCA9ICQoJyNjbG0tbWFpblJhbmdlREQnKS5rZW5kb0Ryb3BEb3duTGlzdCh7XG5cdFx0XHRkYXRhVGV4dEZpZWxkOiAnbGFiZWwnLFxuXHRcdFx0ZGF0YVZhbHVlRmllbGQ6ICd2YWx1ZScsXG5cdFx0XHRkYXRhU291cmNlOiBpdGVtcyxcblx0XHRcdGluZGV4OiAwLFxuXHRcdFx0Ly92YWx1ZVRlbXBsYXRlOiAnPHNwYW4gY2xhc3M9XCJ0ZXh0LW11dGVkIHByLTFcIj5MYXN0IDwvc3Bhbj48c3Bhbj4jOmRhdGEudGV4dCM8L3NwYW4+Jyxcblx0XHRcdGNoYW5nZTogJC5wcm94eSh0aGlzLl9vbk1haW5SYW5nZUNoYW5nZSwgdGhpcylcblx0XHR9KS5kYXRhKCdrZW5kb0Ryb3BEb3duTGlzdCcpO1xuXG5cdFx0JCgnI2NsbS1tYWluUmFuZ2VDb250YWluZXInKS5oaWRlKCk7XG5cblx0XHR0aGlzLl9jaGFydFJhbmdlREQgPSAkKCcjY2xtLWNoYXJ0UmFuZ2VERCcpLmtlbmRvRHJvcERvd25MaXN0KHtcblx0XHRcdGRhdGFUZXh0RmllbGQ6ICdsYWJlbCcsXG5cdFx0XHRkYXRhVmFsdWVGaWVsZDogJ3ZhbHVlJyxcblx0XHRcdGRhdGFTb3VyY2U6IGl0ZW1zLFxuXHRcdFx0aW5kZXg6IDAsXG5cdFx0XHQvL3ZhbHVlVGVtcGxhdGU6ICc8c3BhbiBjbGFzcz1cInRleHQtbXV0ZWQgcHItMVwiPkxhc3QgPC9zcGFuPjxzcGFuPiM6ZGF0YS50ZXh0Izwvc3Bhbj4nLFxuXHRcdFx0Y2hhbmdlOiAkLnByb3h5KHRoaXMuX29uQ2hhcnRSYW5nZUNoYW5nZSwgdGhpcylcblx0XHR9KS5kYXRhKCdrZW5kb0Ryb3BEb3duTGlzdCcpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBsb2JieSBzdGF0ZSBpbmZvXG5cdFx0JCgnI2NsbS1sb2JieVN0YXRlJykuaGlkZSgpO1xuXG5cdFx0Ly8gQ29uZmlndXJlIHNjYWxlLXVwIG1vZGFsXG5cdFx0JCgnI2NsbS1zY2FsZVVwTW9kYWwnKS5tb2RhbCh7XG5cdFx0XHRiYWNrZHJvcDogJ3N0YXRpYycsXG5cdFx0XHRrZXlib2FyZDogZmFsc2UsXG5cdFx0XHRzaG93OiBmYWxzZSxcblx0XHR9KTtcblxuXHRcdC8vIEluaXQgbm9kZXMnIG51bWJlciBudW1lcmljIHN0ZXBwZXIgaW4gc2NhbGUtdXAgbW9kYWxcblx0XHR0aGlzLl9udW1Ob2Rlc0luID0gJCgnI2NsbS1udW1Ob2Rlc05TJykua2VuZG9OdW1lcmljVGV4dEJveCh7XG5cdFx0ICAgIG1pbjogMSxcblx0XHRcdG1heDogNSxcblx0XHQgICAgc3RlcDogMSxcblx0XHQgICAgZm9ybWF0OiAnIydcblx0XHR9KS5kYXRhKCdrZW5kb051bWVyaWNUZXh0Qm94Jyk7XG5cblx0XHQvLyBJbml0aWFsaXplIGtlbmRvIHZhbGlkYXRpb24gb24gc2NhbGUtdXAgZm9ybVxuXHRcdHRoaXMuX3NjYWxlVXBWYWxpZGF0b3IgPSAkKCcjY2xtLXNjYWxlVXBGb3JtJykua2VuZG9WYWxpZGF0b3Ioe30pLmRhdGEoJ2tlbmRvVmFsaWRhdG9yJyk7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXIgZm9yIHNjYWxlLXVwIHBhbmVsIGhpZGVcblx0XHQkKCcjY2xtLXNjYWxlVXBNb2RhbCcpLm9uKCdoaWRkZW4uYnMubW9kYWwnLCAkLnByb3h5KHRoaXMuX29uU2NhbGVVcE1vZGFsSGlkZGVuLCB0aGlzKSk7XG5cblx0XHQvLyBJbml0aWFsaXplIG9yY2hlc3RyYXRpb24gbG9nIGdyaWRcblx0XHR0aGlzLl9sb2dHcmlkID0gJCgnI2NsbS1sb2dHcmlkJykua2VuZG9HcmlkKHtcblx0XHRcdGRhdGFTb3VyY2U6IFtdLFxuXHRcdFx0cmVzaXphYmxlOiB0cnVlLFxuXHRcdFx0c2VsZWN0YWJsZTogZmFsc2UsXG5cdFx0XHRub1JlY29yZHM6IHtcblx0XHRcdFx0dGVtcGxhdGU6ICdObyBlbnRyaWVzLidcblx0XHRcdH0sXG5cdFx0XHRjb2x1bW5zOiBbXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRmaWVsZDogJ3RpbWVzdGFtcCcsXG5cdFx0XHRcdFx0dGl0bGU6ICdUaW1lc3RhbXAnLFxuXHRcdFx0XHRcdHdpZHRoOiAxODBcblx0XHRcdFx0fSxcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGZpZWxkOiAnbGV2ZWwnLFxuXHRcdFx0XHRcdHRpdGxlOiAnTGV2ZWwnLFxuXHRcdFx0XHRcdHdpZHRoOiAxMDBcblx0XHRcdFx0fSxcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGZpZWxkOiAnbWVzc2FnZScsXG5cdFx0XHRcdFx0dGl0bGU6ICdNZXNzYWdlJyxcblx0XHRcdFx0XHR3aWR0aDogNDAwXG5cdFx0XHRcdH0sXG5cdFx0XHRdLFxuXHRcdFx0ZGF0YUJvdW5kOiBmdW5jdGlvbigpIHtcblx0XHRcdCAgICB0aGlzLmNvbnRlbnQuc2Nyb2xsVG9wKHRoaXMudGJvZHkuaGVpZ2h0KCkpOyAvLyBTY3JvbGwgdG8gYm90dG9tXG5cdFx0XHR9XG5cdFx0fSkuZGF0YSgna2VuZG9HcmlkJyk7XG5cblx0XHQkKCcjY2xtX21heExvZ01zZ3MnKS50ZXh0KHRoaXMuTUFYX0xPR19TSVpFKTtcblxuXHRcdC8vIEluaXRpYWxpemUgaGVscCB0b29sdGlwc1xuXHRcdCQodGhpcykua2VuZG9Ub29sdGlwKHtcblx0XHRcdGZpbHRlcjogJ2lbdGl0bGVdLmhlbHAnLFxuXHRcdFx0cG9zaXRpb246ICdyaWdodCcsXG5cdFx0XHRjb250ZW50OiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdHJldHVybiBgPGRpdiBjbGFzcz1cImhlbHAtdG9vbHRpcFwiPiR7ZS50YXJnZXQuZGF0YSgndGl0bGUnKX08L2Rpdj5gO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHQvLyBSZXF1ZXN0IG5vZGVzIGxpc3QgdG8gc2VydmVyXG5cdFx0dGhpcy5fcmVxdWVzdE5vZGVzTGlzdCgpO1xuXG5cdFx0Ly8gU2NoZWR1bGUgY29udGludW91cyBkYXRhIHJlcXVlc3QgZm9yIHRoZSBzZWxlY3RlZCBub2Rlc1xuXHRcdHRoaXMuX3JlcXVlc3REYXRhVGltZXIgPSBzZXRJbnRlcnZhbCgkLnByb3h5KHRoaXMuX29uUmVxdWVzdERhdGFJbnRlcnZhbCwgdGhpcyksIDYwMDAwKTsgLy8gMSBtaW51dGVcblxuXHRcdC8vIFJlcXVlc3Qgb3JjaGVzdHJhdGlvbiBsb2dzIHRvIHNlcnZlclxuXHRcdHRoaXMuX3JlcXVlc3RPcmNoZXN0cmF0aW9uTG9ncygpO1xuXG5cdFx0Ly8gU2NoZWR1bGUgY29udGludW91cyBvcmNoZXN0cmF0aW9uIGxvZ3MgcmVxdWVzdFxuXHRcdHRoaXMuX3JlcXVlc3RMb2dzVGltZXIgPSBzZXRJbnRlcnZhbCgkLnByb3h5KHRoaXMuX3JlcXVlc3RPcmNoZXN0cmF0aW9uTG9ncywgdGhpcyksIDMwMDApOyAvLyAzIHNlY29uZHNcblx0fVxuXG5cdGRlc3Ryb3koKVxuXHR7XG5cdFx0Ly8gQ2FsbCBzdXBlciBtZXRob2Rcblx0XHRzdXBlci5kZXN0cm95KCk7XG5cblx0XHQvLyBEZXN0cm95IHNjcm9sbGluZyB0YWJzXG5cdFx0JCgnI2NsbS10YWJOYXZpZ2F0b3IgI3RhYnMnKS5zY3JvbGxpbmdUYWJzKCdkZXN0cm95Jyk7XG5cblx0XHQvLyBIaWRlIG1vZGFsc1xuXHRcdCQoJyNjbG0tY2hhcnRNb2RhbCcpLm1vZGFsKCdoaWRlJyk7XG5cdFx0JCgnI2NsbS1zY2FsZVVwTW9kYWwnKS5tb2RhbCgnaGlkZScpO1xuXG5cdFx0Ly8gUmVtb3ZlIGNsaWNrIGxpc3RlbmVyc1xuXHRcdCQoJyNjbG0tcmVmcmVzaEJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyNjbG0tc2NhbGVVcEJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyNjbG0tc2NhbGVVcE1vZGFsQnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI2NsbS1ub2RlTWluaUNoYXJ0c0NvbnRhaW5lcicpLm9mZignY2hhcnRDbGljaycpO1xuXG5cdFx0Ly8gUmVtb3ZlIHNjYWxlLXVwIHBhbmVsIGxpc3RlbmVyXG5cdFx0JCgnI2NsbS1zY2FsZVVwTW9kYWwnKS5vZmYoJ2hpZGRlbi5icy5tb2RhbCcpO1xuXG5cdFx0Ly8gQ2xlYXIgbm9kZXMsIGRhdGEgYW5kIGxvZ3MgcmVxdWVzdCBzY2hlZHVsaW5nXG5cdFx0Y2xlYXJUaW1lb3V0KHRoaXMuX3JlcXVlc3ROb2Rlc1RpbWVyKTtcblx0XHRjbGVhckludGVydmFsKHRoaXMuX3JlcXVlc3REYXRhVGltZXIpO1xuXHRcdGNsZWFySW50ZXJ2YWwodGhpcy5fcmVxdWVzdExvZ3NUaW1lcik7XG5cdH1cblxuXHRvbkV4dGVuc2lvbkNvbW1hbmQoY29tbWFuZCwgZGF0YSlcblx0e1xuXHRcdGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9OT0RFUylcblx0XHR7XG5cdFx0XHRsZXQgbm9kZXNPYmogPSBkYXRhLmdldFNGU0FycmF5KCdub2RlcycpO1xuXG5cdFx0XHRsZXQgbm9kZXMgPSBbXTtcblx0XHRcdGxldCBub2Rlc0lkcyA9IFtdO1xuXG5cdFx0XHRmb3IgKGxldCBpID0gMDsgaSA8IG5vZGVzT2JqLnNpemUoKTsgaSsrKVxuXHRcdFx0e1xuXHRcdFx0XHRsZXQgbm9kZSA9IG5vZGVzT2JqLmdldFNGU0FycmF5KGkpO1xuXG5cdFx0XHRcdG5vZGVzSWRzLnB1c2gobm9kZS5nZXRVdGZTdHJpbmcoMCkpO1xuXG5cdFx0XHRcdG5vZGVzLnB1c2goe1xuXHRcdFx0XHRcdCdpZCc6IG5vZGUuZ2V0VXRmU3RyaW5nKDApLFxuXHRcdFx0XHRcdCdhbGlhcyc6IG5vZGUuZ2V0VXRmU3RyaW5nKDEpLCAvLyBTZXQgaW4gbm9kZSBjb25maWd1cmF0aW9uLCBidXQgY2FuJ3QgYmUgZWRpdGVkIC0gY291bGQgYmUgcmVtb3ZlZFxuXHRcdFx0XHRcdCduYW1lJzogbm9kZS5nZXRVdGZTdHJpbmcoMiksIC8vIElQIGFkZHJlc3Mgb3IgZG9tYWluIG5hbWVcblx0XHRcdFx0XHQncm9vbXMnOiBub2RlLmdldEludCgzKSxcblx0XHRcdFx0XHQnY2N1Jzogbm9kZS5nZXRJbnQoNCksXG5cdFx0XHRcdFx0J3RocmVhZHMnOiBub2RlLmdldEludCg1KSxcblx0XHRcdFx0XHQnY3B1Jzogbm9kZS5nZXREb3VibGUoNiksXG5cdFx0XHRcdFx0J3VzZWRNZW0nOiBub2RlLmdldExvbmcoNyksXG5cdFx0XHRcdFx0J2FsbG9jTWVtJzogbm9kZS5nZXRMb25nKDgpLFxuXHRcdFx0XHRcdCduZXRJbic6IG5vZGUuZ2V0TG9uZyg5KSxcblx0XHRcdFx0XHQnbmV0T3V0Jzogbm9kZS5nZXRMb25nKDEwKSxcblx0XHRcdFx0XHQnam9pblRpbWUnOiBub2RlLmdldExvbmcoMTEpLFxuXHRcdFx0XHRcdCdoZWFsdGgnOiBub2RlLmdldEJvb2woMTIpLFxuXHRcdFx0XHRcdCdhY3RpdmUnOiBub2RlLmdldEJvb2woMTMpLCAvLyBVc2VkIGZvciBncm91cGluZ1xuXHRcdFx0XHRcdCdyZWN5Y2xhYmxlJzogbm9kZS5nZXRCb29sKDE0KSxcblx0XHRcdFx0XHQndGVybWluYWJsZSc6IG5vZGUuZ2V0Qm9vbCgxNSksXG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBHZXQgbm9kZXMgZ3JpZCBkYXRhc291cmNlXG5cdFx0XHRsZXQgZHMgPSB0aGlzLl9ncmlkLmRhdGFTb3VyY2U7XG5cblx0XHRcdC8vIC0tLSBSRU1PVkUgTk9ERVMgLS0tXG5cblx0XHRcdGxldCBzZWxmID0gdGhpcztcblx0XHRcdCQubWFwKGRzLmRhdGEoKSwgZnVuY3Rpb24gKGRhdGFJdGVtLCBpbmRleCkge1xuXHRcdFx0XHRpZiAoZGF0YUl0ZW0gJiYgIW5vZGVzSWRzLmluY2x1ZGVzKGRhdGFJdGVtWydpZCddKSlcblx0XHRcdFx0e1xuXHRcdFx0XHRcdC8vIFJlbW92ZSBub2RlIGZyb20gZGF0YXN0b3JlXG5cdFx0XHRcdFx0ZHMucmVtb3ZlKGRhdGFJdGVtKTtcblxuXHRcdFx0XHRcdC8vIFJlbW92ZSBub2RlIGZyb20gbGlzdCBvZiBzZWxlY3RlZCBub2RlcyAoaWYgc2VsZWN0ZWQpXG5cdFx0XHRcdFx0c2VsZi5fc2VsZWN0ZWROb2RlcyA9IHNlbGYuX3NlbGVjdGVkTm9kZXMuZmlsdGVyKHggPT4geCAhPT0gZGF0YUl0ZW1bJ2lkJ10pO1xuXHRcdFx0XHRcdHNlbGYuX3NlbGVjdGVkQWN0aXZlTm9kZXMgPSBzZWxmLl9zZWxlY3RlZEFjdGl2ZU5vZGVzLmZpbHRlcih4ID0+IHggIT09IGRhdGFJdGVtWydpZCddKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cblx0XHRcdC8vIFVwZGF0ZSBub2RlcyBjaGFydHMgdmlldyBhbmQgbm9kZXMgZGVhY3RpdmF0ZSBidXR0b24sIGluIGNhc2UgYSBzZWxlY3RlZCBub2RlIHdhcyByZW1vdmVkXG5cdFx0XHR0aGlzLl91cGRhdGVDaGFydGVkTm9kZXMoKTtcblx0XHRcdHRoaXMuX3VwZGF0ZURlYWN0aXZhdGVCdXR0b24oKTtcblxuXHRcdFx0Ly8gLS0tIEFERC9VUERBVEUgTk9ERVMgLS0tXG5cblx0XHRcdGxldCBhY3RpdmVOb2Rlc0NudCA9IDA7XG5cblx0XHRcdGZvciAobGV0IG5vZGUgb2Ygbm9kZXMpXG5cdFx0XHR7XG5cdFx0XHRcdHZhciBkYXRhSXRlbSA9IGRzLmdldChub2RlLmlkKTtcblxuXHRcdFx0XHQvLyBVcGRhdGUgbm9kZVxuXHRcdFx0XHRpZiAoZGF0YUl0ZW0pXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRkYXRhSXRlbS5zZXQoJ3Jvb21zJywgbm9kZS5yb29tcyk7XG5cdFx0XHRcdFx0ZGF0YUl0ZW0uc2V0KCdjY3UnLCBub2RlLmNjdSk7XG5cdFx0XHRcdFx0ZGF0YUl0ZW0uc2V0KCd0aHJlYWRzJywgbm9kZS50aHJlYWRzKTtcblx0XHRcdFx0XHRkYXRhSXRlbS5zZXQoJ2NwdScsIG5vZGUuY3B1KTtcblx0XHRcdFx0XHRkYXRhSXRlbS5zZXQoJ3VzZWRNZW0nLCBub2RlLnVzZWRNZW0pO1xuXHRcdFx0XHRcdGRhdGFJdGVtLnNldCgnYWxsb2NNZW0nLCBub2RlLmFsbG9jTWVtKTtcblx0XHRcdFx0XHRkYXRhSXRlbS5zZXQoJ25ldEluJywgbm9kZS5uZXRJbik7XG5cdFx0XHRcdFx0ZGF0YUl0ZW0uc2V0KCduZXRPdXQnLCBub2RlLm5ldE91dCk7XG5cdFx0XHRcdFx0ZGF0YUl0ZW0uc2V0KCdqb2luVGltZScsIG5vZGUuam9pblRpbWUpO1xuXHRcdFx0XHRcdGRhdGFJdGVtLnNldCgnaGVhbHRoJywgbm9kZS5oZWFsdGgpO1xuXHRcdFx0XHRcdGRhdGFJdGVtLnNldCgnYWN0aXZlJywgbm9kZS5hY3RpdmUpO1xuXHRcdFx0XHRcdGRhdGFJdGVtLnNldCgncmVjeWNsYWJsZScsIG5vZGUucmVjeWNsYWJsZSk7XG5cdFx0XHRcdFx0ZGF0YUl0ZW0uc2V0KCd0ZXJtaW5hYmxlJywgbm9kZS50ZXJtaW5hYmxlKTtcblxuXHRcdFx0XHRcdGRhdGFJdGVtLmRpcnR5ID0gZmFsc2U7IC8vIEhpZGVzIFwiZGlydHlcIiBpbmRpY2F0b3IgaW4gZ3JpZFxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQWRkIG5vZGVcblx0XHRcdFx0ZWxzZVxuXHRcdFx0XHQgXHRkcy5hZGQobm9kZSk7XG5cblx0XHRcdFx0Ly8gQ291bnQgYWN0aXZlIG5vZGVzXG5cdFx0XHRcdGlmIChub2RlLmFjdGl2ZSlcblx0XHRcdFx0XHRhY3RpdmVOb2Rlc0NudCsrO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBSZWZyZXNoIGdyaWRcblx0XHRcdHRoaXMuX2dyaWQucmVmcmVzaCgpO1xuXG5cdFx0XHQvLyBEaXNwbGF5IGdsb2JhbCB2YWx1ZXNcblx0XHRcdCQoJyNjbG0tdG90YWxBY3RpdmVOb2RlcycpLnRleHQoYWN0aXZlTm9kZXNDbnQpO1xuXHRcdFx0JCgnI2NsbS10b3RhbEluYWN0aXZlTm9kZXMnKS50ZXh0KG5vZGVzLmxlbmd0aCAtIGFjdGl2ZU5vZGVzQ250KTtcblx0XHRcdCQoJyNjbG0tdG90YWxDY3VMb2JieScpLnRleHQoZGF0YS5nZXRJbnQoJ2NjdUxvYmJ5JykpO1xuXHRcdFx0JCgnI2NsbS10b3RhbENjdU5vZGVzJykudGV4dChkYXRhLmdldEludCgnY2N1Tm9kZXMnKSk7XG5cdFx0XHQkKCcjY2xtLXRvdGFsUm9vbXMnKS50ZXh0KGRhdGEuZ2V0SW50KCdyb29tcycpKTtcblxuXHRcdFx0Ly8gU2hvdyBsb2JieSBzdGF0ZVxuXHRcdFx0dGhpcy5fc2hvd0xvYmJ5U3RhdGUoZGF0YS5nZXRCb29sKCdhY3RpdmUnKSk7XG5cdFx0fVxuXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfTk9ERVNfREFUQSlcblx0XHR7XG5cdFx0XHRsZXQgc3RhdHMgPSBkYXRhLmdldFNGU0FycmF5KCdzdGF0cycpO1xuXHRcdFx0bGV0IGkgPSB0aGlzLl9tYWluUmFuZ2VERC52YWx1ZSgpO1xuXHRcdFx0bGV0IGludGVydmFsTWlsbGlzID0gdGhpcy5pbnRlcnZhbHNbaV0ubWludXRlcyAqIDYwICogMTAwMDtcblxuXHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBzdGF0cy5zaXplKCk7IGkrKylcblx0XHRcdHtcblx0XHRcdFx0bGV0IG5vZGVTdGF0cyA9IHN0YXRzLmdldFNGU09iamVjdChpKTtcblxuXHRcdFx0XHQvLyBHZXQgbm9kZSBpZFxuXHRcdFx0XHRsZXQgaWQgPSBub2RlU3RhdHMuZ2V0VXRmU3RyaW5nKCdpZCcpO1xuXG5cdFx0XHRcdC8vIEdldCBjaGFydHMgaXRlbSBmb3Igbm9kZVxuXHRcdFx0XHRsZXQgaXRlbSA9IHRoaXMucXVlcnlTZWxlY3RvcignI2NsbS1ub2RlTWluaUNoYXJ0c0NvbnRhaW5lciAjbm9kZV8nICsgaWQpO1xuXG5cdFx0XHRcdGlmIChpdGVtKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0aXRlbS5hZGRDaGFydEVudHJpZXMoJ2NjdScsIG5vZGVTdGF0cy5nZXRTRlNPYmplY3QoJ2NjdScpLCBudWxsLCBpbnRlcnZhbE1pbGxpcyk7XG5cdFx0XHRcdFx0aXRlbS5hZGRDaGFydEVudHJpZXMoJ2NwdScsIG5vZGVTdGF0cy5nZXRTRlNPYmplY3QoJ2NwdScpLCBudWxsLCBpbnRlcnZhbE1pbGxpcyk7XG5cdFx0XHRcdFx0aXRlbS5hZGRDaGFydEVudHJpZXMoJ21lbScsIG5vZGVTdGF0cy5nZXRTRlNPYmplY3QoJ21lbScpLCBudWxsLCBpbnRlcnZhbE1pbGxpcyk7XG5cdFx0XHRcdFx0aXRlbS5hZGRDaGFydEVudHJpZXMoJ3RoZCcsIG5vZGVTdGF0cy5nZXRTRlNPYmplY3QoJ3RoZCcpLCBudWxsLCBpbnRlcnZhbE1pbGxpcyk7XG5cdFx0XHRcdFx0aXRlbS5hZGRDaGFydEVudHJpZXMoJ25ldCcsIG5vZGVTdGF0cy5nZXRTRlNPYmplY3QoJ25ldE91dCcpLCBub2RlU3RhdHMuZ2V0U0ZTT2JqZWN0KCduZXRJbicpLCBpbnRlcnZhbE1pbGxpcyk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRlbHNlIGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9DSEFSVF9EQVRBKVxuXHRcdHtcblx0XHRcdGxldCBjaGFydERhdGEgPSBkYXRhLmdldFNGU09iamVjdCgnY2hhcnQnKTtcblx0XHRcdGxldCBpID0gdGhpcy5fY2hhcnRSYW5nZURELnZhbHVlKCk7XG5cdFx0XHRsZXQgaW50ZXJ2YWxNaWxsaXMgPSB0aGlzLmludGVydmFsc1tpXS5taW51dGVzICogNjAgKiAxMDAwO1xuXG5cdFx0XHQvLyBHZXQgbm9kZSBpZCBhbmQgY2hhcnQgdHlwZVxuXHRcdFx0bGV0IGlkID0gY2hhcnREYXRhLmdldFV0ZlN0cmluZygnaWQnKTtcblx0XHRcdGxldCB0eXBlID0gY2hhcnREYXRhLmdldFV0ZlN0cmluZygndHlwZScpO1xuXG5cdFx0XHRpZiAodGhpcy5fY2hhcnRJbmZvICYmIHRoaXMuX2NoYXJ0SW5mby5pZCA9PSBpZCAmJiB0aGlzLl9jaGFydEluZm8udHlwZSA9PSB0eXBlKVxuXHRcdFx0e1xuXHRcdFx0XHRzd2l0Y2ggKHR5cGUpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRjYXNlICduZXQnOlxuXHRcdFx0XHRcdFx0dGhpcy5fYWRkRGV0YWlsQ2hhcnRFbnRyaWVzKGNoYXJ0RGF0YS5nZXRTRlNPYmplY3QoJ25ldE91dCcpLCBjaGFydERhdGEuZ2V0U0ZTT2JqZWN0KCduZXRJbicpLCBpbnRlcnZhbE1pbGxpcyk7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0XHR0aGlzLl9hZGREZXRhaWxDaGFydEVudHJpZXMoY2hhcnREYXRhLmdldFNGU09iamVjdCh0eXBlKSwgbnVsbCwgaW50ZXJ2YWxNaWxsaXMpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfTE9HX01FU1NBR0VTKVxuXHRcdHtcblx0XHRcdGxldCBsb2dFbnRyaWVzID0gZGF0YS5nZXRTRlNBcnJheSgnZW50cmllcycpO1xuXHRcdFx0XG5cdFx0XHRmb3IgKGxldCBlID0gMDsgZSA8IGxvZ0VudHJpZXMuc2l6ZSgpOyBlKyspXG5cdFx0XHR7XG5cdFx0XHRcdGxldCBsb2dFbnRyeSA9IGxvZ0VudHJpZXMuZ2V0U0ZTT2JqZWN0KGUpO1xuXG5cdFx0XHRcdGxldCBlbGUgPSB7XG5cdFx0XHRcdFx0dGltZXN0YW1wOiBrZW5kby50b1N0cmluZyhuZXcgRGF0ZShsb2dFbnRyeS5nZXRMb25nKCd0aW1lJykpLCAnZGQvTU0veXl5eSBISDptbTpzcycpLFxuXHRcdFx0XHRcdGxldmVsOiBsb2dFbnRyeS5nZXRVdGZTdHJpbmcoJ2xldmVsJyksXG5cdFx0XHRcdFx0bWVzc2FnZTogbG9nRW50cnkuZ2V0VXRmU3RyaW5nKCdtc2cnKSxcblx0XHRcdFx0fTtcblxuXHRcdFx0XHRsZXQgZHMgPSB0aGlzLl9sb2dHcmlkLmRhdGFTb3VyY2U7XG5cdFx0XHRcdGRzLmFkZChlbGUpO1xuXG5cdFx0XHRcdC8vIENoZWNrIGl0ZW1zIGxpbWl0XG5cdFx0XHRcdHdoaWxlIChkcy50b3RhbCgpID4gdGhpcy5NQVhfTE9HX1NJWkUpXG5cdFx0XHRcdFx0ZHMucmVtb3ZlKGRzLmF0KDApKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRvblVwdGltZVVwZGF0ZWQodmFsdWVzKVxuXHR7XG5cdFx0dGhpcy5fdXB0aW1lU2VjcyA9IHZhbHVlc1szXTtcblx0XHR0aGlzLl91cHRpbWVTZWNzICs9ICh2YWx1ZXNbMl0gKiA2MCk7XG5cdFx0dGhpcy5fdXB0aW1lU2VjcyArPSAodmFsdWVzWzFdICogNjAgKiA2MCk7XG5cblx0XHQkKCcjY2xtLXVwdGltZURheXMnKS50ZXh0KCAodmFsdWVzWzBdIDw9IDkgPyAnMDAnIDogKHZhbHVlc1swXSA8PSA5OSA/ICcwJyA6ICcnKSkgKyB2YWx1ZXNbMF0gKTtcblx0XHQkKCcjY2xtLXVwdGltZUhvdXJzJykudGV4dCggKHZhbHVlc1sxXSA8PSA5ID8gJzAnIDogJycpICsgdmFsdWVzWzFdICk7XG5cdFx0JCgnI2NsbS11cHRpbWVNaW51dGVzJykudGV4dCggKHZhbHVlc1syXSA8PSA5ID8gJzAnIDogJycpICsgdmFsdWVzWzJdICk7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBVSSBFVkVOVCBMSVNURU5FUlNcblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRfb25Ob2Rlc0dyaWRDaGFuZ2UoZSwgYXJncylcblx0e1xuXHRcdGxldCBncmlkID0gZS5zZW5kZXI7XG5cdFx0bGV0IGl0ZW1zID0gZ3JpZC5pdGVtcygpO1xuXG5cdFx0dGhpcy5fc2VsZWN0ZWROb2RlcyA9IFtdO1xuXHRcdHRoaXMuX3NlbGVjdGVkQWN0aXZlTm9kZXMgPSBbXTtcblxuXHRcdGZvciAobGV0IGkgb2YgZ3JpZC5zZWxlY3QoKSlcblx0XHR7XG5cdFx0XHRsZXQgZGF0YUl0ZW0gPSBncmlkLmRhdGFJdGVtKGkpO1xuXHRcdFx0dGhpcy5fc2VsZWN0ZWROb2Rlcy5wdXNoKGRhdGFJdGVtWydpZCddKTtcblxuXHRcdFx0aWYgKGRhdGFJdGVtWydhY3RpdmUnXSlcblx0XHRcdFx0dGhpcy5fc2VsZWN0ZWRBY3RpdmVOb2Rlcy5wdXNoKGRhdGFJdGVtWydpZCddKTtcblx0XHR9XG5cblx0XHQvLyBDb21wYXJlIHRoZSBsaXN0IG9mIHNlbGVjdGVkIG5vZGVzIHdpdGggdGhlIGxpc3Qgb2YgdmlzaWJsZVxuXHRcdC8vIGNoYXJ0IHJvd3MsIHRvIHNob3cvaGlkZSB0aGUgc2VsZWN0ZWQvZGVzZWxlY3RlZCBvbmVzXG5cdFx0dGhpcy5fdXBkYXRlQ2hhcnRlZE5vZGVzKCk7XG5cblx0XHQvLyBFbmFibGUvZGlzYWJsZSBidXR0b24gdG8gZGVhY3RpdmF0ZSBzZWxlY3RlZCBhY3RpdmUgbm9kZXNcblx0XHR0aGlzLl91cGRhdGVEZWFjdGl2YXRlQnV0dG9uKCk7XG5cdH1cblxuXHRfb25Ob2Rlc0dyaWREYXRhQm91bmQoZSlcblx0e1xuXHRcdGxldCBncmlkID0gZS5zZW5kZXI7XG5cdFx0bGV0IGl0ZW1zID0gZ3JpZC5pdGVtcygpO1xuXHRcdGxldCBpdGVtc1RvU2VsZWN0ID0gW107XG5cdFx0bGV0IHNlbGYgPSB0aGlzO1xuXG5cdFx0aXRlbXMuZWFjaChmdW5jdGlvbiAoaWR4LCByb3cpIHtcblx0XHRcdGxldCBkYXRhSXRlbSA9IGdyaWQuZGF0YUl0ZW0ocm93KTtcblx0XHRcdGlmIChzZWxmLl9zZWxlY3RlZE5vZGVzLmluY2x1ZGVzKGRhdGFJdGVtWydpZCddKSkge1xuXHRcdFx0IFx0aXRlbXNUb1NlbGVjdC5wdXNoKHJvdyk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHRlLnNlbmRlci5zZWxlY3QoaXRlbXNUb1NlbGVjdCk7XG5cblx0XHQvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cblx0XHQvLyBIaWRlIGdyb3VwIGNvbHVtbiBhbmQgY29sbGFwc2UgaWNvblxuXHRcdCQoJyNjbG0tbm9kZXNMaXN0IC5rLWdyb3VwLWNvbCwgI2NsbS1ub2Rlc0xpc3QgLmstZ3JvdXAtY2VsbCcpLnJlbW92ZSgpO1xuXHRcdGxldCBzcGFuQ2VsbHMgPSAkKCcjY2xtLW5vZGVzTGlzdCAuay1ncm91cGluZy1yb3cnKS5jaGlsZHJlbigndGQnKTtcblx0XHRzcGFuQ2VsbHMuYXR0cignY29sc3BhbicsIHNwYW5DZWxscy5hdHRyKCdjb2xzcGFuJykgLSAxKTtcblx0XHQkKCcjY2xtLW5vZGVzTGlzdCAuay1pY29uLmstaS1jb2xsYXBzZScpLmhpZGUoKTtcblxuXHRcdC8vIE1vZGlmeSBncm91cCBsYWJlbFxuXHRcdCQoJyNjbG0tbm9kZXNMaXN0IC5rLWdyb3VwaW5nLXJvdyB0ZCBwLmstcmVzZXQnKS5lYWNoKGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHRcdGlmICgkKHRoaXMpLnRleHQoKSA9PSAnYWN0aXZlOiB0cnVlJylcblx0XHRcdFx0JCh0aGlzKS50ZXh0KCdBY3RpdmUgbm9kZXMnKTtcblx0XHRcdGVsc2Vcblx0XHRcdFx0JCh0aGlzKS50ZXh0KCdJbmFjdGl2ZSBub2RlcycpO1xuXHRcdH0pO1xuXHR9XG5cblx0X29uTWFpblJhbmdlQ2hhbmdlKGUpXG5cdHtcblx0XHQvLyBSZXF1ZXN0IG5vZGVzIGRhdGEgdG8gc2VydmVyXG5cdFx0dGhpcy5fcmVxdWVzdE5vZGVzRGF0YSgpO1xuXHR9XG5cblx0X29uQ2hhcnRSYW5nZUNoYW5nZShlKVxuXHR7XG5cdFx0Ly8gUmVxdWVzdCBkZXRhaWwgY2hhcnQgZGF0YSB0byBzZXJ2ZXJcblx0XHR0aGlzLl9yZXF1ZXN0RGV0YWlsQ2hhcnREYXRhKCk7XG5cdH1cblxuXHRfb25SZXF1ZXN0RGF0YUludGVydmFsKClcblx0e1xuXHRcdC8vIFJlcXVlc3Qgc2VsZWN0ZWQgbm9kZXMgZGF0YVxuXHRcdHRoaXMuX3JlcXVlc3ROb2Rlc0RhdGEoKTtcblxuXHRcdC8vIFJlcXVlc3QgZGV0YWlsIGNoYXJ0IGRhdGFcblx0XHR0aGlzLl9yZXF1ZXN0RGV0YWlsQ2hhcnREYXRhKCk7XG5cdH1cblxuXHRfcmVxdWVzdE5vZGVzTGlzdCgpXG5cdHtcblx0XHQvLyBDbGVhciBwcmV2aW91cyByZXF1ZXN0IHNjaGVkdWxpbmdcblx0XHRjbGVhclRpbWVvdXQodGhpcy5fcmVxdWVzdE5vZGVzVGltZXIpO1xuXG5cdFx0Ly8gQ2hlY2sgaWYgY29ubmVjdGlvbiBpcyBzdGlsbCBhdmFpbGFibGVcblx0XHRpZiAodGhpcy5zbWFydEZveC5pc0Nvbm5lY3RlZClcblx0XHR7XG5cdFx0XHQvLyBTZW5kIHJlcXVlc3QgdG8gZXh0ZW5zaW9uXG5cdFx0XHR0aGlzLnNlbmRFeHRlbnNpb25SZXF1ZXN0KHRoaXMuUkVRX0dFVF9OT0RFUyk7XG5cblx0XHRcdC8vIFNjaGVkdWxlIG5leHQgcmVxdWVzdFxuXHRcdFx0dGhpcy5fcmVxdWVzdE5vZGVzVGltZXIgPSBzZXRUaW1lb3V0KCQucHJveHkodGhpcy5fcmVxdWVzdE5vZGVzTGlzdCwgdGhpcyksIDUwMDApOyAvLyBFdmVyeSA1IHNlY29uZHNcblx0XHR9XG5cdH1cblxuXHRfb25NaW5pQ2hhcnRDbGljayhlKVxuXHR7XG5cdFx0bGV0IG5vZGVJZCA9IGUuZGV0YWlsLm5vZGU7XG5cdFx0bGV0IG5vZGVEYXRhSXRlbSA9IHRoaXMuX2dyaWQuZGF0YVNvdXJjZS5nZXQobm9kZUlkKTtcblx0XHRsZXQgY2hhcnRUeXBlID0gZS5kZXRhaWwudHlwZTtcblx0XHRsZXQgY2hhcnRPcHRpb25zID0gZS5kZXRhaWwub3B0aW9ucztcblxuXHRcdC8vIFNhdmUgcmVmIHRvIGNoYXJ0ZWQgbm9kZVxuXHRcdHRoaXMuX2NoYXJ0SW5mbyA9IHtcblx0XHRcdGlkOiBub2RlSWQsXG5cdFx0XHR0eXBlOiBjaGFydFR5cGVcblx0XHR9O1xuXG5cdFx0Ly8gRXh0cmFjdCBjaGFydCB0aXRsZSBmcm9tIG9wdGlvbnNcblx0XHQkKCcjY2xtLWNoYXJ0TW9kYWxUaXRsZScpLnRleHQoY2hhcnRPcHRpb25zLnRpdGxlLnRleHQpO1xuXG5cdFx0aWYgKG5vZGVEYXRhSXRlbS5hbGlhcylcblx0XHR7XG5cdFx0XHQkKCcjY2xtLWNoYXJ0Tm9kZUFsaWFzJykudGV4dChub2RlRGF0YUl0ZW0uYWxpYXMpO1xuXHRcdFx0JCgnI2NsbS1jaGFydE5vZGVOYW1lJykudGV4dChub2RlRGF0YUl0ZW0ubmFtZSk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHQkKCcjY2xtLWNoYXJ0Tm9kZUFsaWFzJykudGV4dChub2RlRGF0YUl0ZW0ubmFtZSk7XG5cdFx0XHQkKCcjY2xtLWNoYXJ0Tm9kZU5hbWUnKS5oaWRlKCk7XG5cdFx0fVxuXG5cdFx0Ly8gU2V0IHNlY29uZGFyeSByYW5nZSBkcm9wZG93biB0byBtYWluIHJhbmdlIHZhbHVlXG5cdFx0bGV0IGluZGV4ID0gdGhpcy5fbWFpblJhbmdlREQuc2VsZWN0KCk7XG5cdFx0dGhpcy5fY2hhcnRSYW5nZURELnNlbGVjdChpbmRleCk7XG5cblx0XHQvLyBDcmVhdGUgY2hhcnQgdGFnXG5cdFx0JCgnI2NsbS1ub2RlRGV0YWlsQ2hhcnRDb250YWluZXInKS5hcHBlbmQoJCgnPGRpdj4nLCB7J2NsYXNzJzogJ2NoYXJ0J30pKVxuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBjaGFydFxuXHRcdHRoaXMuX2dldENoYXJ0VGFnKCkua2VuZG9DaGFydCh7XG5cdFx0XHR0cmFuc2l0aW9uczogZmFsc2UsXG5cdFx0XHRjaGFydEFyZWE6IHtcblx0XHRcdFx0YmFja2dyb3VuZDogJ3RyYW5zcGFyZW50Jyxcblx0XHRcdFx0bWFyZ2luOiAwLFxuXHRcdFx0ICAgIHBhZGRpbmc6MFxuXHRcdFx0fSxcblx0ICAgICAgICBsZWdlbmQ6IHtcblx0ICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgc2VyaWVzRGVmYXVsdHM6IHtcblx0ICAgICAgICAgICAgdHlwZTogJ3NjYXR0ZXJMaW5lJyxcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZSxcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG5cdCAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiAndHJhbnNwYXJlbnQnXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1pc3NpbmdWYWx1ZXM6ICdnYXAnLFxuXHRcdFx0XHRtYXJrZXJzOiB7XG5cdFx0XHQgICAgICB2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHQgIHR5cGU6ICdjaXJjbGUnLFxuXHRcdFx0XHQgIHNpemU6IDMsXG5cdFx0XHQgICAgfSxcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHNlcmllczogY2hhcnRPcHRpb25zLnNlcmllcyxcblx0ICAgICAgICB5QXhpczogY2hhcnRPcHRpb25zLnlBeGlzLFxuXHQgICAgICAgIHhBeGlzOiB7XG5cdFx0XHRcdG1ham9yR3JpZExpbmVzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtYWpvclRpY2tzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogdHJ1ZVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsYWJlbHM6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHRcdHJvdGF0aW9uOiAwLFxuXHRcdFx0XHRcdHRlbXBsYXRlOiAnIzoga2VuZG8udG9TdHJpbmcobmV3IERhdGUodmFsdWUpLCBcIkhIOm1tXCIpICMnXG5cdFx0XHRcdH0sXG5cdCAgICAgICAgfSxcblx0XHRcdHRvb2x0aXA6IGNoYXJ0T3B0aW9ucy50b29sdGlwXG5cdCAgICB9KS5kYXRhKCdrZW5kb0NoYXJ0Jyk7XG5cblx0XHQvLyBDbGVhciBjaGFydFxuXHRcdHRoaXMuX2dldENoYXJ0V2lkZ2V0KCkuc2V0RGF0YVNvdXJjZShudWxsKTtcblxuXHRcdC8vIERpc3BsYXkgY2hhcnQgbW9kYWxcblx0XHQkKCcjY2xtLWNoYXJ0TW9kYWwnKS5tb2RhbCgnc2hvdycpO1xuXG5cdFx0Ly8gUmVxdWVzdCBkZXRhaWwgY2hhcnQgZGF0YSB0byBzZXJ2ZXJcblx0XHR0aGlzLl9yZXF1ZXN0RGV0YWlsQ2hhcnREYXRhKCk7XG5cdH1cblxuXHRfb25DaGFydE1vZGFsSGlkZGVuKGUpXG5cdHtcblx0XHQvLyBEZXN0cm95IGNoYXJ0XG5cdFx0dGhpcy5fY2hhcnRJbmZvID0gbnVsbDtcblxuXHRcdCQoJyNjbG0tY2hhcnRNb2RhbFRpdGxlJykudGV4dCgnJyk7XG5cdFx0JCgnI2NsbS1jaGFydE5vZGVBbGlhcycpLnRleHQoJycpO1xuXHRcdCQoJyNjbG0tY2hhcnROb2RlTmFtZScpLnRleHQoJycpO1xuXG5cdFx0dGhpcy5fZ2V0Q2hhcnRXaWRnZXQoKS5kZXN0cm95KCk7XG5cdFx0dGhpcy5fZ2V0Q2hhcnRUYWcoKS5yZW1vdmUoKTtcblx0fVxuXG5cdF9yZXF1ZXN0T3JjaGVzdHJhdGlvbkxvZ3MoKVxuXHR7XG5cdFx0Ly8gQnVpbGQgcmVxdWVzdCBwYXJhbWV0ZXJzXG5cdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblx0XHRwYXJhbXMucHV0TG9uZygndHMnLCB0aGlzLl9sYXN0TG9nc1JlcVRpbWVzdGFtcCk7XG5cblx0XHQvLyBTZW5kIHJlcXVlc3QgdG8gZXh0ZW5zaW9uXG5cdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9HRVRfTE9HX01FU1NBR0VTLCBwYXJhbXMpO1xuXG5cdFx0Ly8gVXBkYXRlIGxhc3QgcmVxdWVzdCB0aW1lXG5cdFx0dGhpcy5fbGFzdExvZ3NSZXFUaW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8gUFJJVkFURSBNRVRIT0RTXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0X3VwZGF0ZUNoYXJ0ZWROb2RlcygpXG5cdHtcblx0XHQvLyBHZXQgc2VsZWN0ZWQgbm9kZXMgbm90IHlldCBzaG93biBpbiB0aGUgY2hhcnQgYXJlYVxuXHRcdGxldCB0b1Nob3cgPSB0aGlzLl9zZWxlY3RlZE5vZGVzLmZpbHRlcih4ID0+ICF0aGlzLl9jaGFydGVkTm9kZXMuaW5jbHVkZXMoeCkpO1xuXG5cdFx0Ly8gR2V0IG5vZGVzIHNob3duIGluIHRoZSBjaGFydCBhcmVhIG5vdCBpbiB0aGUgc2VsZWN0ZWQgbGlzdCBhbnltb3JlXG5cdFx0bGV0IHRvSGlkZSA9IHRoaXMuX2NoYXJ0ZWROb2Rlcy5maWx0ZXIoeCA9PiAhdGhpcy5fc2VsZWN0ZWROb2Rlcy5pbmNsdWRlcyh4KSk7XG5cblx0XHQvLyBTaG93IG5vZGVzIGNoYXJ0c1xuXHRcdGlmICh0b1Nob3cubGVuZ3RoID4gMClcblx0XHR7XG5cdFx0XHQvL2NvbnNvbGUubG9nKFwiU0hPV0lORyBDSEFSVFMgT0YgTk9ERVM6IFwiICsgdG9TaG93KVxuXHRcdFx0dGhpcy5fY2hhcnRlZE5vZGVzID0gWy4uLnRoaXMuX2NoYXJ0ZWROb2RlcywgLi4udG9TaG93XTsgLy8gTWVyZ2UgYXJyYXlzXG5cblx0XHRcdC8vIERpc3BsYXkgbm9kZSBjaGFydHNcblx0XHRcdGZvciAobGV0IGlkIG9mIHRvU2hvdylcblx0XHRcdFx0dGhpcy5fZGlzcGxheU5vZGVDaGFydHNJdGVtKGlkKTtcblx0XHR9XG5cblx0XHQvLyBIaWRlIG5vZGVzIGNoYXJ0c1xuXHRcdGlmICh0b0hpZGUubGVuZ3RoID4gMClcblx0XHR7XG5cdFx0XHQvL2NvbnNvbGUubG9nKFwiSElESU5HIENIQVJUUyBPRiBOT0RFUzogXCIgKyB0b0hpZGUpXG5cdFx0XHR0aGlzLl9jaGFydGVkTm9kZXMgPSB0aGlzLl9jaGFydGVkTm9kZXMuZmlsdGVyKHggPT4gIXRvSGlkZS5pbmNsdWRlcyh4KSk7XG5cblx0XHRcdC8vIFJlbW92ZSBub2RlIGNoYXJ0c1xuXHRcdFx0Zm9yIChsZXQgaWQgb2YgdG9IaWRlKVxuXHRcdFx0e1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVOb2RlQ2hhcnRzSXRlbShpZCk7XG5cblx0XHRcdFx0Ly8gUmVtb3ZlIGRldGFpbCBjaGFydCBpZiB2aXNpYmxlXG5cdFx0XHRcdGlmICh0aGlzLl9jaGFydEluZm8gJiYgaWQgPT0gdGhpcy5fY2hhcnRJbmZvLmlkKVxuXHRcdFx0XHRcdCQoJyNjbG0tY2hhcnRNb2RhbCcpLm1vZGFsKCdoaWRlJyk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gU2hvdy9oaWRlIGludGVydmFsIGRyb3Bkb3duXG5cdFx0aWYgKHRvU2hvdy5sZW5ndGggPiAwIHx8IHRvSGlkZS5sZW5ndGggPiAwKVxuXHRcdHtcblx0XHRcdGlmICh0aGlzLl9jaGFydGVkTm9kZXMubGVuZ3RoID4gMClcblx0XHRcdFx0JCgnI2NsbS1tYWluUmFuZ2VDb250YWluZXInKS5zaG93KCk7XG5cdFx0XHRlbHNlXG5cdFx0XHRcdCQoJyNjbG0tbWFpblJhbmdlQ29udGFpbmVyJykuaGlkZSgpO1xuXHRcdH1cblxuXHRcdC8vIFJlcXVlc3QgY2hhcnRzIGRhdGEgZm9yIG5ld2x5IHNlbGVjdGVkIG5vZGVzXG5cdFx0Ly8gTk9URTogd2UgaGF2ZSB0byB1c2UgYSB0aW1lb3V0IGFzIGEgd29ya2Fyb3VuZCB0byBnaXZlIGNoYXJ0cyB0aW1lIHRvIGJlIHJlbmRlcmVkIGJlZm9yZSBkcmF3aW5nIHRoZW0sIG9yIHRoZXkgd2lsbCBleGNlZWQgdGhlaXIgY29udGFpbmVyJ3Mgd2lkdGhcblx0XHRpZiAodG9TaG93Lmxlbmd0aCA+IDApXG5cdFx0XHRzZXRUaW1lb3V0KCQucHJveHkodGhpcy5fcmVxdWVzdE5vZGVzRGF0YSwgdGhpcyksIDIwLCB0b1Nob3cpO1xuXHR9XG5cblx0X2dldFRpbWVTaW5jZUpvaW5UZW1wbGF0ZShkYXRhSXRlbSlcblx0e1xuXHRcdGxldCBub3cgPSBtb21lbnQoKTtcblx0XHRsZXQgam9pblRpbWUgPSBtb21lbnQoZGF0YUl0ZW1bJ2pvaW5UaW1lJ10pO1xuXG5cdFx0bGV0IGRpZmZEYXlzID0gbm93LmRpZmYoam9pblRpbWUsICdkYXlzJyk7XG5cdFx0bGV0IGRpZmZIb3VycyA9IG5vdy5kaWZmKGpvaW5UaW1lLCAnaG91cnMnKSAtIChkaWZmRGF5cyAqIDI0KTtcblx0XHRsZXQgZGlmZk1pbnV0ZXMgPSBub3cuZGlmZihqb2luVGltZSwgJ21pbnV0ZXMnKSAtICgoKGRpZmZEYXlzICogMjQpICsgZGlmZkhvdXJzKSAqIDYwKTtcblxuXHRcdHJldHVybiBgPHNwYW4+JHtkaWZmRGF5c31kICR7ZGlmZkhvdXJzfWggJHtkaWZmTWludXRlc31tPHNwYW4+YDtcblx0fVxuXG5cdF9nZXRIZWFsdGhUZW1wbGF0ZShkYXRhSXRlbSlcblx0e1xuXHRcdGxldCBzdHlsZSA9ICd0ZXh0LXN1Y2Nlc3MnO1xuXG5cdFx0aWYgKCFkYXRhSXRlbVsnaGVhbHRoJ10pXG5cdFx0XHRzdHlsZSA9ICd0ZXh0LWRhbmdlcic7XG5cblx0XHRyZXR1cm4gYDxzcGFuIGNsYXNzPVwiJHtzdHlsZX1cIj48aSBjbGFzcz1cImZhcyBmYS1jaXJjbGVcIj48L2k+PC9zcGFuPmA7XG5cdH1cblxuXHRfZ2V0UmVjeWNsYWJsZVRlbXBsYXRlKGRhdGFJdGVtKVxuXHR7XG5cdFx0bGV0IHN0eWxlID0gZGF0YUl0ZW1bJ3JlY3ljbGFibGUnXSA/ICd0ZXh0LXN1Y2Nlc3MnIDogJ3RleHQtbGlnaHQnO1xuXHRcdHJldHVybiBgPHNwYW4gY2xhc3M9XCIke3N0eWxlfVwiPjxpIGNsYXNzPVwiZmFzIGZhLWNpcmNsZVwiPjwvaT48L3NwYW4+YDtcblx0fVxuXG5cdF9nZXRUZXJtaW5hYmxlVGVtcGxhdGUoZGF0YUl0ZW0pXG5cdHtcblx0XHRsZXQgc3R5bGUgPSBkYXRhSXRlbVsndGVybWluYWJsZSddID8gJ3RleHQtc3VjY2VzcycgOiAndGV4dC1saWdodCc7XG5cdFx0cmV0dXJuIGA8c3BhbiBjbGFzcz1cIiR7c3R5bGV9XCI+PGkgY2xhc3M9XCJmYXMgZmEtY2lyY2xlXCI+PC9pPjwvc3Bhbj5gO1xuXHR9XG5cblx0X3Nob3dMb2JieVN0YXRlKGlzQWN0aXZlKVxuXHR7XG5cdFx0aWYgKGlzQWN0aXZlKVxuXHRcdHtcblx0XHRcdCQoJyNjbG0tbG9iYnlTdGF0ZSAuYWN0aXZlJykuc2hvdygpO1xuXHRcdFx0JCgnI2NsbS1sb2JieVN0YXRlIC5pbmFjdGl2ZScpLmhpZGUoKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdCQoJyNjbG0tbG9iYnlTdGF0ZSAuYWN0aXZlJykuaGlkZSgpO1xuXHRcdFx0JCgnI2NsbS1sb2JieVN0YXRlIC5pbmFjdGl2ZScpLnNob3coKTtcblx0XHR9XG5cblx0XHQkKCcjY2xtLWxvYmJ5U3RhdGUnKS5zaG93KCk7XG5cblx0XHQvLyBFbmFibGUvZGlzYWJsZSBzY2FsZS11cCBidXR0b25cblx0XHQkKCcjY2xtLXNjYWxlVXBCdCcpLnByb3AoJ2Rpc2FibGVkJywgIWlzQWN0aXZlKTtcblx0fVxuXG5cdF9yZXF1ZXN0Tm9kZXNEYXRhKG5vZGVzID0gbnVsbClcblx0e1xuXHRcdGlmIChub2RlcyA9PSBudWxsKVxuXHRcdFx0bm9kZXMgPSB0aGlzLl9jaGFydGVkTm9kZXM7XG5cblx0XHQvL2NvbnNvbGUubG9nKFwiUkVRVUVTVElORyBEQVRBIEZPUiBOT0RFUyBcIiArIG5vZGVzICsgXCIgKGxhc3QgXCIgKyB0aGlzLmludGVydmFsc1t0aGlzLl9tYWluUmFuZ2VERC52YWx1ZSgpXS5taW51dGVzICsgXCIgbWludXRlcylcIilcblxuXHRcdGlmIChub2Rlcy5sZW5ndGggPiAwICYmIHRoaXMuc21hcnRGb3guaXNDb25uZWN0ZWQpXG5cdFx0e1xuXHRcdFx0bGV0IGkgPSB0aGlzLl9tYWluUmFuZ2VERC52YWx1ZSgpO1xuXHRcdFx0bGV0IGludGVydmFsTWlsbGlzID0gdGhpcy5pbnRlcnZhbHNbaV0ubWludXRlcyAqIDYwICogMTAwMDtcblx0XHRcdGxldCBkYXRhUG9pbnRzID0gdGhpcy5pbnRlcnZhbHNbaV0ucG9pbnRzMTtcblxuXHRcdFx0Ly8gTGlzdCBub2Rlc1xuXHRcdFx0bGV0IGxpc3QgPSBuZXcgU0ZTMlguU0ZTQXJyYXkoKTtcblxuXHRcdFx0Zm9yIChsZXQgbm9kZUlkIG9mIG5vZGVzKVxuXHRcdFx0e1xuXHRcdFx0XHRsZXQgb2JqID0gbmV3IFNGUzJYLlNGU09iamVjdCgpO1xuXHRcdFx0XHRvYmoucHV0VXRmU3RyaW5nKCdpZCcsIG5vZGVJZCk7XG5cdFx0XHRcdG9iai5wdXRMb25nKCdpbnQnLCBpbnRlcnZhbE1pbGxpcyk7XG5cdFx0XHRcdG9iai5wdXRJbnQoJ3B0cycsIGRhdGFQb2ludHMpO1xuXG5cdFx0XHRcdGxpc3QuYWRkU0ZTT2JqZWN0KG9iaik7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEJ1aWxkIHJlcXVlc3QgcGFyYW1ldGVyc1xuXHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblx0XHRcdHBhcmFtcy5wdXRTRlNBcnJheSgnbm9kZXMnLCBsaXN0KTtcblxuXHRcdFx0Ly8gU2VuZCByZXF1ZXN0IHRvIEV4dGVuc2lvblxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9HRVRfTk9ERVNfREFUQSwgcGFyYW1zKTtcblx0XHR9XG5cdH1cblxuXHRfcmVxdWVzdERldGFpbENoYXJ0RGF0YSgpXG5cdHtcblx0XHRpZiAodGhpcy5fY2hhcnRJbmZvKVxuXHRcdHtcblx0XHRcdGxldCBpID0gdGhpcy5fY2hhcnRSYW5nZURELnZhbHVlKCk7XG5cblx0XHRcdGxldCBwYXJhbXMgPSBuZXcgU0ZTMlguU0ZTT2JqZWN0KCk7XG5cdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCdpZCcsIHRoaXMuX2NoYXJ0SW5mby5pZCk7XG5cdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCd0eXBlJywgdGhpcy5fY2hhcnRJbmZvLnR5cGUpO1xuXHRcdFx0cGFyYW1zLnB1dExvbmcoJ2ludCcsIHRoaXMuaW50ZXJ2YWxzW2ldLm1pbnV0ZXMgKiA2MCAqIDEwMDApO1xuXHRcdFx0cGFyYW1zLnB1dEludCgncHRzJywgdGhpcy5pbnRlcnZhbHNbaV0ucG9pbnRzMik7XG5cblx0XHRcdC8vIFNlbmQgcmVxdWVzdCB0byBFeHRlbnNpb25cblx0XHRcdHRoaXMuc2VuZEV4dGVuc2lvblJlcXVlc3QodGhpcy5SRVFfR0VUX0NIQVJUX0RBVEEsIHBhcmFtcyk7XG5cdFx0fVxuXHR9XG5cblx0X3JlbW92ZU5vZGVDaGFydHNJdGVtKG5vZGVJZClcblx0e1xuXHRcdGxldCBlbGVtZW50ID0gdGhpcy5xdWVyeVNlbGVjdG9yKCcjY2xtLW5vZGVNaW5pQ2hhcnRzQ29udGFpbmVyICNub2RlXycgKyBub2RlSWQpO1xuXG5cdFx0Ly8gRGVzdHJveSBlbGVtZW50XG5cdFx0ZWxlbWVudC5kZXN0cm95KCk7XG5cblx0XHQvLyBSZW1vdmUgZWxlbWVudCBmcm9tIGNvbnRhaW5lclxuXHRcdHRoaXMucXVlcnlTZWxlY3RvcignI2NsbS1ub2RlTWluaUNoYXJ0c0NvbnRhaW5lcicpLnJlbW92ZUNoaWxkKGVsZW1lbnQpO1xuXHR9XG5cblx0X2Rpc3BsYXlOb2RlQ2hhcnRzSXRlbShub2RlSWQpXG5cdHtcblx0XHRsZXQgbm9kZURhdGFJdGVtID0gdGhpcy5fZ3JpZC5kYXRhU291cmNlLmdldChub2RlSWQpO1xuXG5cdFx0Ly8gQ3JlYXRlIGVsZW1lbnRcblx0XHRsZXQgZWxlbWVudCA9IG5ldyBOb2RlTWluaUNoYXJ0cyhub2RlRGF0YUl0ZW1bJ2lkJ10sIG5vZGVEYXRhSXRlbVsnYWxpYXMnXSwgbm9kZURhdGFJdGVtWyduYW1lJ10pO1xuXG5cdFx0Ly8gQXBwZW5kIGVsZW1lbnQgdG8gY29udGFpbmVyXG5cdFx0dGhpcy5xdWVyeVNlbGVjdG9yKCcjY2xtLW5vZGVNaW5pQ2hhcnRzQ29udGFpbmVyJykuYXBwZW5kQ2hpbGQoZWxlbWVudCk7XG5cdH1cblxuXHRfZ2V0Q2hhcnRUYWcoKVxuXHR7XG5cdFx0cmV0dXJuICQoJyNjbG0tY2hhcnRNb2RhbCAuY2hhcnQnKTtcblx0fVxuXG5cdF9nZXRDaGFydFdpZGdldCgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fZ2V0Q2hhcnRUYWcoKS5kYXRhKCdrZW5kb0NoYXJ0Jyk7XG5cdH1cblxuXHRfYWRkRGV0YWlsQ2hhcnRFbnRyaWVzKGRhdGEsIGRhdGExLCBpbnRlcnZhbE1pbGxpcylcblx0e1xuXHRcdGxldCBsYXN0VGltZXN0YW1wID0gZGF0YS5nZXRMb25nKCdsYXN0Jyk7XG5cdFx0bGV0IHZhbHVlcyA9IGRhdGEuZ2V0TG9uZ0FycmF5KCdkYXRhJyk7XG5cdFx0bGV0IHZhbHVlczEgPSAoZGF0YTEgIT0gbnVsbCA/IGRhdGExLmdldExvbmdBcnJheSgnZGF0YScpIDogbnVsbCk7XG5cdFx0bGV0IGNoYXJ0V2lkZ2V0ID0gdGhpcy5fZ2V0Q2hhcnRXaWRnZXQoKTtcblxuXHRcdC8vIERpdmlkZSBpbnRlcnZhbCBieSB0aGUgbnVtYmVyIG9mIGRhdGEgcG9pbnRzIHRvIGNhbGN1bGF0ZSB0aGVpciB0aW1lc3RhbXBzXG5cdFx0bGV0IHNsaWNlTWlsbGlzID0gTWF0aC5yb3VuZChpbnRlcnZhbE1pbGxpcyAvIHZhbHVlcy5sZW5ndGgpO1xuXG5cdFx0bGV0IGRzID0gbmV3IGtlbmRvLmRhdGEuRGF0YVNvdXJjZSgpO1xuXHRcdGxldCBmaXJzdFRpbWVzdGFtcCA9IGxhc3RUaW1lc3RhbXAgLSBpbnRlcnZhbE1pbGxpcztcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdmFsdWVzLmxlbmd0aDsgaSsrKVxuXHRcdHtcblx0XHRcdGxldCB0aW1lc3RhbXAgPSBmaXJzdFRpbWVzdGFtcCArIChzbGljZU1pbGxpcyAqIGkpO1xuXG5cdFx0XHRsZXQgdmFsdWUgPSB2YWx1ZXNbaV0gPCAwID8gbnVsbCA6IHZhbHVlc1tpXTtcblx0XHRcdGxldCB2YWx1ZTEgPSB2YWx1ZXMxID8gKHZhbHVlczFbaV0gPCAwID8gbnVsbCA6IHZhbHVlczFbaV0pIDogbnVsbDtcblxuXHRcdFx0bGV0IGVudHJ5ID0ge1xuXHRcdFx0XHR0czogdGltZXN0YW1wLFxuXHRcdFx0XHR2YWw6IHZhbHVlLFxuXHRcdFx0XHR2YWwxOiB2YWx1ZTEsXG5cdFx0XHR9O1xuXG5cdFx0XHRkcy5hZGQoZW50cnkpO1xuXHRcdH1cblxuXHRcdC8vIFNldCBjaGFydCdzIHgtYXhpcyBsaW1pdHNcblx0XHRjaGFydFdpZGdldC5vcHRpb25zLnhBeGlzLm1pbiA9IGZpcnN0VGltZXN0YW1wO1xuXHRcdGNoYXJ0V2lkZ2V0Lm9wdGlvbnMueEF4aXMubWF4ID0gbGFzdFRpbWVzdGFtcDtcblxuXHRcdGNoYXJ0V2lkZ2V0LnNldERhdGFTb3VyY2UoZHMpO1xuXHR9XG5cblx0X3VwZGF0ZURlYWN0aXZhdGVCdXR0b24oKVxuXHR7XG5cdFx0bGV0IGNudCA9IHRoaXMuX3NlbGVjdGVkQWN0aXZlTm9kZXMubGVuZ3RoO1xuXHRcdGxldCB0eHQgPSAoY250ID4gMCA/IGNudCA6ICcnKSArICcgbm9kZScgKyAoY250ICE9IDEgPyAncycgOiAnJyk7XG5cblx0XHQkKCcjY2xtLWRlYWN0aXZhdGVCdCcpLnByb3AoJ2Rpc2FibGVkJywgY250ID09IDApO1xuXHRcdCQoJyNjbG0tZGVhY3RpdmF0ZU5vZGVzTnVtJykudGV4dCh0eHQpO1xuXHR9XG5cblx0X29uRGVhY3RpdmF0ZUJ0Q2xpY2soKVxuXHR7XG5cdFx0dGhpcy5zaGVsbEN0cmwuc2hvd0NvbmZpcm1XYXJuaW5nKGBBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gZGVhY3RpdmF0ZSB0aGUgc2VsZWN0ZWQgYWN0aXZlIG5vZGUke3RoaXMuX3NlbGVjdGVkQWN0aXZlTm9kZXMubGVuZ3RoID4gMSA/ICdzJyA6ICcnfT8gVGhpcyBvcGVyYXRpb24gaXMgaXJyZXZlcnNpYmxlLmAsICQucHJveHkodGhpcy5fb25EZWFjdGl2YXRlTm9kZXNDb25maXJtLCB0aGlzKSk7XG5cdH1cblxuXHRfb25EZWFjdGl2YXRlTm9kZXNDb25maXJtKClcblx0e1xuXHRcdGlmICh0aGlzLl9zZWxlY3RlZEFjdGl2ZU5vZGVzLmxlbmd0aCA+IDAgICYmIHRoaXMuc21hcnRGb3guaXNDb25uZWN0ZWQpXG5cdFx0e1xuXHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblx0XHRcdHBhcmFtcy5wdXRVdGZTdHJpbmdBcnJheSgnbm9kZXMnLCB0aGlzLl9zZWxlY3RlZEFjdGl2ZU5vZGVzKTtcblxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9ERUFDVElWQVRFX05PREVTLCBwYXJhbXMpO1xuXHRcdH1cblx0fVxuXG5cdF9vblNjYWxlVXBCdENsaWNrKClcblx0e1xuXHRcdC8vIERpc3BsYXkgc2NhbGUtdXAgbW9kYWxcblx0XHQkKCcjY2xtLXNjYWxlVXBNb2RhbCcpLm1vZGFsKCdzaG93Jyk7XG5cdH1cblxuXHRfb25TY2FsZVVwQ29uZmlybUJ0Q2xpY2soKVxuXHR7XG5cdFx0aWYgKHRoaXMuX3NjYWxlVXBWYWxpZGF0b3IudmFsaWRhdGUoKSlcblx0XHR7XG5cdFx0XHQvLyBSZXRyaWV2ZSBzY2FsZS11cCBkZXRhaWxzXG5cdFx0XHRsZXQgcGFyYW1zID0gbmV3IFNGUzJYLlNGU09iamVjdCgpO1xuXHRcdFx0cGFyYW1zLnB1dEludCgnbnVtJywgdGhpcy5fbnVtTm9kZXNJbi52YWx1ZSgpKTtcblxuXHRcdFx0Ly8gU2VuZCBzY2FsZS11cCByZXF1ZXN0IHRvIHNlcnZlclxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9TQ0FMRV9VUCwgcGFyYW1zKTtcblxuXHRcdFx0Ly8gSGlkZSBtb2RhbFxuXHRcdFx0JCgnI2NsbS1zY2FsZVVwTW9kYWwnKS5tb2RhbCgnaGlkZScpO1xuXHRcdH1cblx0fVxuXG5cdF9vblNjYWxlVXBNb2RhbEhpZGRlbihlKVxuXHR7XG5cdFx0Ly8gUmVzZXQgdmFsaWRhdG9yXG5cdFx0dGhpcy5fc2NhbGVVcFZhbGlkYXRvci5oaWRlTWVzc2FnZXMoKTtcblxuXHRcdC8vIFRoZSBtZXRob2QgYWJvdmUgZG9lc24ndCByZW1vdmUgdGhlIGstaW52YWxpZCBjbGFzc2VzIGFuZCBhcmlhLWludmFsaWQ9XCJ0cnVlXCIgYXR0cmlidXRlcyBmcm9tIGlucHV0c1xuXHRcdC8vIExldCdzIGRvIGl0IG1hbnVhbGx5XG5cdFx0JCgnI2NsbS1zY2FsZVVwRm9ybSAuay1pbnZhbGlkJykucmVtb3ZlQ2xhc3MoJ2staW52YWxpZCcpO1xuXHRcdCQoJyNjbG0tc2NhbGVVcEZvcm0gW2FyaWEtaW52YWxpZD1cInRydWVcIl0nKS5yZW1vdmVBdHRyKCdhcmlhLWludmFsaWQnKTtcblxuXHRcdC8vIFJlc2V0IHNjYWxlLXVwIGZvcm1cblx0XHR0aGlzLl9udW1Ob2Rlc0luLnZhbHVlKDEpO1xuXHR9XG5cblxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFBSSVZBVEUgR0VUVEVSU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzFKQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDM2ZBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7OztBIiwic291cmNlUm9vdCI6IiJ9