rubyfox-server 2.17.3.2 → 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 -263
  32. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/catalina.properties +209 -207
  33. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/context.xml +31 -31
  34. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/jaspic-providers.xml +23 -23
  35. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/jaspic-providers.xsd +52 -52
  36. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/keystore.jks +0 -0
  37. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/server.xml +177 -161
  38. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/tomcat-users.xml +18 -7
  39. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/tomcat-users.xsd +59 -59
  40. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/web.xml +4740 -4737
  41. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/annotations-api.jar +0 -0
  42. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ant.jar +0 -0
  43. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ha.jar +0 -0
  44. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ssi.jar +0 -0
  45. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-storeconfig.jar +0 -0
  46. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-tribes.jar +0 -0
  47. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina.jar +0 -0
  48. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/el-api.jar +0 -0
  49. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jasper-el.jar +0 -0
  50. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jasper.jar +0 -0
  51. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jaspic-api.jar +0 -0
  52. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jsp-api.jar +0 -0
  53. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/servlet-api.jar +0 -0
  54. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/sfs2x-ws-helper.jar +0 -0
  55. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-api.jar +0 -0
  56. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-coyote.jar +0 -0
  57. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-dbcp.jar +0 -0
  58. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-cs.jar +0 -0
  59. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-de.jar +0 -0
  60. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-es.jar +0 -0
  61. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-fr.jar +0 -0
  62. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ja.jar +0 -0
  63. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ko.jar +0 -0
  64. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-pt-BR.jar +0 -0
  65. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ru.jar +0 -0
  66. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-zh-CN.jar +0 -0
  67. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-jdbc.jar +0 -0
  68. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-jni.jar +0 -0
  69. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-util-scan.jar +0 -0
  70. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-util.jar +0 -0
  71. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-websocket.jar +0 -0
  72. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/websocket-api.jar +0 -0
  73. data/lib/rubyfox/server/data/lib/javax.activation-1.2.0.jar +0 -0
  74. data/lib/rubyfox/server/data/lib/javax.mail.jar +0 -0
  75. data/lib/rubyfox/server/data/lib/js/JSApi.js +2 -1
  76. data/lib/rubyfox/server/data/lib/js/LibApi.js +181 -48
  77. data/lib/rubyfox/server/data/lib/sfs2x-admin.jar +0 -0
  78. data/lib/rubyfox/server/data/lib/sfs2x-cluster.jar +0 -0
  79. data/lib/rubyfox/server/data/lib/sfs2x-core.jar +0 -0
  80. data/lib/rubyfox/server/data/lib/sfs2x.jar +0 -0
  81. data/lib/rubyfox/server/data/sfs2x-service +26 -30
  82. data/lib/rubyfox/server/data/www/BlueBox.war +0 -0
  83. data/lib/rubyfox/server/data/www/HelloServlet/WEB-INF/web.xml +1 -3
  84. data/lib/rubyfox/server/data/www/ROOT/_css_/default.css +14 -6
  85. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/style.css +44 -2
  86. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/application.bundle.js +98 -61
  87. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/endors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-6~mod-7~mod-8~mod-9.bundle.js +17357 -0
  88. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-0.bundle.js +4 -4
  89. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-1.bundle.js +3 -3
  90. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-10.bundle.js +101 -66
  91. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-11.bundle.js +544 -8
  92. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12.bundle.js +915 -1480
  93. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12~module-15~module-16~module-4.bundle.js +2665 -0
  94. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-13.bundle.js +606 -3093
  95. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-13~module-16~module-17~module-4.bundle.js +2665 -0
  96. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-14.bundle.js +764 -0
  97. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-15.bundle.js +71 -0
  98. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-16.bundle.js +1787 -0
  99. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-17.bundle.js +3383 -0
  100. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-4.bundle.js +121 -1009
  101. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-5.bundle.js +1214 -1744
  102. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-6.bundle.js +398 -666
  103. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-7.bundle.js +717 -192
  104. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-8.bundle.js +2117 -665
  105. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-9.bundle.js +613 -690
  106. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~mod-0~mod-1~mod-10~mod-11~mod-16~mod-5~mod-6~mod-7~mod-8.bundle.js +17357 -0
  107. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-5~mod-6~mod-7~mod-8~mod-9.bundle.js +17357 -0
  108. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/{vendors~module-0~module-1~module-13~module-4~module-5~module-7~module-8.bundle.js → vendors~mod-0~mod-1~mod-11~mod-12~mod-17~mod-5~mod-7~mod-8~mod-9.bundle.js} +2 -2
  109. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-12.bundle.js +807 -0
  110. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-13.bundle.js +807 -0
  111. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-configurator.html +32 -0
  112. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-monitor.html +185 -0
  113. data/lib/rubyfox/server/data/www/ROOT/admin/modules/cluster-updater.html +47 -0
  114. data/lib/rubyfox/server/data/www/ROOT/admin/modules/extension-deployer.html +84 -0
  115. data/lib/rubyfox/server/data/www/ROOT/admin/modules/zone-monitor.html +15 -8
  116. data/lib/rubyfox/server/data/www/ROOT/index.html +13 -23
  117. data/lib/rubyfox/server/data/www/host-manager/META-INF/context.xml +2 -2
  118. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/jsp/404.jsp +2 -2
  119. data/lib/rubyfox/server/data/www/host-manager/{manager.xml → WEB-INF/manager.xml} +5 -1
  120. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/web.xml +17 -0
  121. data/lib/rubyfox/server/data/www/host-manager/css/manager.css +141 -0
  122. data/lib/rubyfox/server/data/www/host-manager/images/tomcat.svg +967 -0
  123. data/lib/rubyfox/server/data/www/manager/META-INF/context.xml +2 -0
  124. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorCerts.jsp +1 -1
  125. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorCiphers.jsp +1 -1
  126. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorTrustedCerts.jsp +1 -1
  127. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/sessionDetail.jsp +3 -3
  128. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/sessionsList.jsp +1 -1
  129. data/lib/rubyfox/server/data/www/manager/WEB-INF/web.xml +17 -0
  130. data/lib/rubyfox/server/data/www/manager/css/manager.css +141 -0
  131. data/lib/rubyfox/server/data/www/manager/images/tomcat.svg +967 -0
  132. data/lib/rubyfox/server/data/www/manager/xform.xsl +74 -59
  133. data/lib/rubyfox/server/version.rb +1 -1
  134. metadata +30 -31
  135. data/lib/rubyfox/server/data/config/admin/icons/Analytics.png +0 -0
  136. data/lib/rubyfox/server/data/config/admin/icons/BanManager.png +0 -0
  137. data/lib/rubyfox/server/data/config/admin/icons/BlueBoxMonitor.png +0 -0
  138. data/lib/rubyfox/server/data/config/admin/icons/Console.png +0 -0
  139. data/lib/rubyfox/server/data/config/admin/icons/Dashboard.png +0 -0
  140. data/lib/rubyfox/server/data/config/admin/icons/ExtensionManager.png +0 -0
  141. data/lib/rubyfox/server/data/config/admin/icons/LicenseManager.png +0 -0
  142. data/lib/rubyfox/server/data/config/admin/icons/LogViewer.png +0 -0
  143. data/lib/rubyfox/server/data/config/admin/icons/ServerConfigurator.png +0 -0
  144. data/lib/rubyfox/server/data/config/admin/icons/ServletManager.png +0 -0
  145. data/lib/rubyfox/server/data/config/admin/icons/ZoneConfigurator.png +0 -0
  146. data/lib/rubyfox/server/data/config/admin/icons/ZoneMonitor.png +0 -0
  147. data/lib/rubyfox/server/data/lib/BlueBox.war +0 -0
  148. data/lib/rubyfox/server/data/lib/apache-tomcat/LICENSE +0 -1061
  149. data/lib/rubyfox/server/data/lib/apache-tomcat/NOTICE +0 -68
  150. data/lib/rubyfox/server/data/lib/apache-tomcat/README.md +0 -81
  151. data/lib/rubyfox/server/data/lib/apache-tomcat/RELEASE-NOTES +0 -174
  152. data/lib/rubyfox/server/data/lib/imap.jar +0 -0
  153. data/lib/rubyfox/server/data/lib/mailapi.jar +0 -0
  154. data/lib/rubyfox/server/data/lib/pop3.jar +0 -0
  155. data/lib/rubyfox/server/data/lib/smtp.jar +0 -0
  156. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12~module-13~module-9.bundle.js +0 -2634
  157. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-9.bundle.js +0 -807
  158. data/lib/rubyfox/server/data/www/host-manager/images/tomcat.gif +0 -0
  159. data/lib/rubyfox/server/data/www/manager/images/tomcat.gif +0 -0
  160. /data/lib/rubyfox/server/data/data/buddylists/{BasicExamples/.keep → .keep} +0 -0
@@ -1,536 +1,333 @@
1
1
  /*! (c) gotoAndPlay | All rights reserved */
2
2
  (window["webpackJsonpapplication"] = window["webpackJsonpapplication"] || []).push([["module-9"],{
3
3
 
4
- /***/ "./src/components/module-specific/ssl-certificate-manager.js":
5
- /*!*******************************************************************!*\
6
- !*** ./src/components/module-specific/ssl-certificate-manager.js ***!
7
- \*******************************************************************/
8
- /*! exports provided: SslCertificateManager */
9
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
10
-
11
- "use strict";
12
- __webpack_require__.r(__webpack_exports__);
13
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SslCertificateManager", function() { return SslCertificateManager; });
14
- /* harmony import */ var _utils_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../utils/utilities */ "./src/utils/utilities.js");
15
- /* harmony import */ var aes_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! aes-js */ "./node_modules/aes-js/index.js");
16
- /* harmony import */ var aes_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aes_js__WEBPACK_IMPORTED_MODULE_1__);
17
-
18
-
19
-
20
- class SslCertificateManager extends HTMLElement
21
- {
22
- constructor()
23
- {
24
- super();
25
-
26
- this._modalHtml = `
27
- <div class="modal" id="uploadModal" tabindex="-1" role="dialog" aria-labelledby="uploadModalTitle" aria-hidden="true">
28
- <div class="modal-dialog modal-dialog-centered" role="document">
29
- <div class="modal-content">
30
- <div class="modal-header">
31
- <h5 class="modal-title text-primary" id="uploadModalTitle">SSL Certificate Manager</h5>
32
- <button type="button" class="close" data-dismiss="modal" aria-label="Close">
33
- <span aria-hidden="true">&times;</span>
34
- </button>
35
- </div>
36
- <div class="modal-body in-flow-invalid-msg">
37
- <fieldset id="uploadFieldset">
38
- <div id="uploaderSubform">
39
- <div class="form-group">
40
- <div class="col-form-label form-label-container">
41
- <label for="uploader" class="form-label">Certificate keystore (jks) <i class="fas fa-question-circle text-muted help" title="SSL certificate's protected keystore file to be uploaded to the server, in jks format"></i></label>
42
- </div>
43
- <div class="inner-widget">
44
- <input type="file" id="uploader" name="uploader" accept=".jks" data-upload-msg="Select a file">
45
- <span class="k-invalid-msg position-static" data-for="uploader"></span>
46
- </div>
47
- </div>
48
- </div>
49
- <div id="passwordsSubform">
50
- <div class="form-row">
51
- <div class="form-group col">
52
- <div class="col-form-label form-label-container">
53
- <label for="ksPassword" class="form-label">Keystore password <i class="fas fa-question-circle text-muted help" title="Password used to protect the certificate keystore"></i></label>
54
- </div>
55
- <div class="inner-widget">
56
- <input type="password" id="ksPassword" name="ksPassword" class="form-control k-textbox" autocomplete="off" required data-required-msg="Required" />
57
- <span class="k-invalid-msg position-static" data-for="ksPassword"></span>
58
- </div>
59
- </div>
60
-
61
- <div class="form-group col">
62
- <div class="col-form-label form-label-container">
63
- <label for="confirmKsPassword" class="form-label">Confirm password <i class="fas fa-question-circle text-muted help" title="Keystore password confirmation"></i></label>
64
- </div>
65
- <div class="inner-widget">
66
- <input type="password" id="confirmKsPassword" name="confirmKsPassword" class="form-control k-textbox" autocomplete="off" required data-required-msg="Required" />
67
- <span class="k-invalid-msg position-static" data-for="confirmKsPassword"></span>
68
- </div>
69
- </div>
70
- </div>
71
-
72
- <p><em>For additional security, enter again and confirm your SFS2X administration password.</em></p>
73
-
74
- <div class="form-row">
75
- <div class="form-group col">
76
- <div class="col-form-label form-label-container">
77
- <label for="adminPassword" class="form-label">Admin password <i class="fas fa-question-circle text-muted help" title="SmartFoxServer 2X remote administration password"></i></label>
78
- </div>
79
- <div class="inner-widget">
80
- <input type="password" id="adminPassword" name="adminPassword" class="form-control k-textbox" autocomplete="off" required data-required-msg="Required" />
81
- <span class="k-invalid-msg position-static" data-for="adminPassword"></span>
82
- </div>
83
- </div>
84
-
85
- <div class="form-group col">
86
- <div class="col-form-label form-label-container">
87
- <label for="confirmAdminPassword" class="form-label">Confirm password <i class="fas fa-question-circle text-muted help" title="SmartFoxServer 2X remote administration password confirmation"></i></label>
88
- </div>
89
- <div class="inner-widget">
90
- <input type="password" id="confirmAdminPassword" name="confirmAdminPassword" class="form-control k-textbox" autocomplete="off" required data-required-msg="Required" />
91
- <span class="k-invalid-msg position-static" data-for="confirmAdminPassword"></span>
92
- </div>
93
- </div>
94
- </div>
95
- </div>
96
- </fieldset>
97
- </div>
98
- <div class="modal-footer flex-column">
99
- <div class="d-flex w-100">
100
- <div class="flex-grow-1 text-left">
101
- <button id="uploadSslButton" type="button" class="k-button k-primary"><i class="fas fa-upload mr-1"></i>Upload certificate</button>
102
- <i id="uploadSpinner" class="fas fa-circle-notch fa-spin text-primary align-middle ml-1"></i>
103
- </div>
104
- <div class="flex-grow-1 text-right">
105
- <button type="button" class="k-button k-secondary" data-dismiss="modal">Cancel</button>
106
- </div>
107
- </div>
108
- <div id="uploadErrorMsg" class="text-danger mt-3"></div>
109
- </div>
110
- </div>
111
- </div>
112
- </div>
113
- `;
114
-
115
- //-------------------------------------------
116
-
117
- $(this).append(`
118
- <div class="col-sm-5 col-lg-4 col-form-label form-label-container">
119
- <label class="form-label">Upload certificate <i class="fas fa-question-circle text-muted help" title="Upload an SSL certificate's protected keystore to the server"></i></label>
120
- </div>
121
- <div class="inner-widget align-self-center align-self-sm-start col-auto">
122
- <button id="manageSslButton" type="button" class="k-button k-primary" disabled><i class="fas fa-cog mr-1"></i>Manage</button>
123
- </div>
124
- `);
125
-
126
- // Add listeners to Manage button click
127
- $('#manageSslButton', $(this)).on('click', $.proxy(this._onManageSslClick, this));
128
- }
129
-
130
- destroy()
131
- {
132
- // Remove event listener
133
- $('#manageSslButton', $(this)).off('click');
134
-
135
- // Hide modal (which in turn destroys it)
136
- let modalElement = $('#uploadModal', $(this));
137
-
138
- if (modalElement)
139
- modalElement.modal('hide');
140
- }
141
-
142
- get enabled()
143
- {
144
- return this._isEnabled;
145
- }
146
-
147
- set enabled(value)
148
- {
149
- this._isEnabled = value;
150
-
151
- // Enable/disable Manage button
152
- $('#manageSslButton', $(this)).attr('disabled', !value);
153
-
154
- // Enable/disable modal
155
- let modalElement = $('#uploadModal', $(this));
156
-
157
- if (modalElement)
158
- {
159
- // Disable modal close buttons
160
- $('button[data-dismiss="modal"]', modalElement).attr('disabled', !value);
161
-
162
- // Disable upload button
163
- $('#uploadSslButton', modalElement).attr('disabled', !value);
164
-
165
- // Disable fieldset
166
- $('#uploadFieldset', modalElement).attr('disabled', !value);
167
- }
168
- }
169
-
170
- get uploadTargetConfig()
171
- {
172
- return this._uploadTargetConfig;
173
- }
174
-
175
- set uploadTargetConfig(data)
176
- {
177
- this._uploadTargetConfig = data;
178
- }
179
-
180
- _onManageSslClick()
181
- {
182
- // Initialize and show modal
183
- this._showModal();
184
- }
185
-
186
- _onUploadSslClick()
187
- {
188
- if (this._validate())
189
- this._startSslCertUpload();
190
- }
191
-
192
- _showModal()
193
- {
194
- // Append modal html
195
- $(this).append(this._modalHtml);
196
-
197
- let modalElement = $('#uploadModal', $(this));
198
-
199
- // Hide SSL certificate upload spinner and error message container
200
- $('#uploadSpinner', modalElement).hide();
201
- $('#uploadErrorMsg', modalElement).hide();
202
- $('#uploadErrorMsg', modalElement).text('');
203
-
204
- // Add listener to Upload button click
205
- $('#uploadSslButton', modalElement).on('click', $.proxy(this._onUploadSslClick, this));
206
-
207
- // Add listener to modal hide event
208
- modalElement.on('hidden.bs.modal', $.proxy(this._destroyModal, this));
209
-
210
- // Initialize kendo uploader
211
- this._uploadWidget = modalElement.find('#uploader').kendoUpload({
212
- allowedExtensions: ['.jks'],
213
- multiple: false,
214
- template: function(dataItem) {
215
- dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
216
- return kendo.template(`
217
- <span class='k-progress w-100'></span>
218
- <span class="">
219
- <span class="k-file-name" title="#=name#">#=name#</span>
220
- <span class="k-file-size">Size: #=bytesToSize(size, 1, 'Bytes')#</span>
221
- </span>
222
- `)(dataItem);
223
- },
224
- localization: {
225
- select: 'Select file...'
226
- }
227
- }).data('kendoUpload');
228
-
229
- // Initialize kendo validation on uploader subform
230
- // NOTE: we use separate validators to be able to disable 'validateOnBlur' on the uploader,
231
- // because it causes the error message to appear as soon as the "Select file" button is clicked
232
- this._validator1 = modalElement.find('#uploaderSubform').kendoValidator({
233
- validateOnBlur: false,
234
- rules: {
235
- upload: function(input) {
236
- let valid = false;
237
- if (input.is('[type=file]'))
238
- valid = input.closest('.k-upload').find('.k-file').length > 0;
239
-
240
- return valid;
241
- }
242
- }
243
- }).data('kendoValidator');
244
-
245
- // Initialize kendo validation on passwords subform
246
- this._validator2 = modalElement.find('#passwordsSubform').kendoValidator({
247
- validateOnBlur: true,
248
- rules: {
249
- verifyKsPassword: $.proxy(function(input) {
250
- let valid = true;
251
- if (input.is('[name=confirmKsPassword]'))
252
- valid = input.val() === $(this).find('#ksPassword').val();
253
- return valid;
254
- }, this),
255
- verifyAdmPassword: $.proxy(function(input) {
256
- let valid = true;
257
- if (input.is('[name=confirmAdminPassword]'))
258
- valid = input.val() === $(this).find('#adminPassword').val();
259
- return valid;
260
- }, this)
261
- },
262
- messages: {
263
- verifyKsPassword: 'Password not matching',
264
- verifyAdmPassword: 'Password not matching',
265
- }
266
- }).data('kendoValidator');
267
-
268
- // Initialize bootstrap modal
269
- modalElement.modal({
270
- backdrop: 'static',
271
- keyboard: false,
272
- });
273
- }
274
-
275
- _destroyModal()
276
- {
277
- let modalElement = $('#uploadModal', $(this));
278
-
279
- if (modalElement)
280
- {
281
- // Remove listeners
282
- $('#uploadSslButton', modalElement).off('click');
283
- modalElement.off('hidden.bs.modal');
284
-
285
- // Destroy everything Kendo
286
- kendo.destroy(modalElement);
287
-
288
- // Dispose modal
289
- modalElement.modal('dispose');
290
-
291
- // Remove html
292
- modalElement.remove();
293
- modalElement = null;
294
- }
295
- }
296
-
297
- _validate()
298
- {
299
- let val1 = this._validator1.validate();
300
- let val2 = this._validator2.validate();
301
-
302
- return val1 && val2;
303
- }
304
-
305
- _startSslCertUpload()
306
- {
307
- if (!this._uploadTargetConfig)
308
- throw new Error('Upload target configuration not set');
309
-
310
- let modalElement = $('#uploadModal', $(this));
311
-
312
- if (modalElement)
313
- {
314
- let certData = {};
315
- certData.file = this._uploadWidget.getFiles()[0];
316
- certData.ksPassword = $('#ksPassword', modalElement).val();
317
- certData.adminPassword = $('#adminPassword', modalElement).val();
318
-
319
- // Disable modal
320
- this.enabled = false;
321
-
322
- // Hide previous error and show spinner
323
- $('#uploadSpinner', modalElement).show();
324
- $('#uploadErrorMsg', modalElement).hide();
325
- $('#uploadErrorMsg', modalElement).text('');
326
-
327
- //=================================================================
328
-
329
- // Generate Init Vector
330
- let rngValues = [];
331
- for (let i = 0; i < 16; i++)
332
- rngValues.push(Math.floor(Math.random() * 256));
333
-
334
- let iv = new Uint8Array(rngValues);
335
-
336
- // Generate secret key by MD5-encoding admin password + session token
337
- let md5Pass = this._binaryMD5(certData.adminPassword + this._uploadTargetConfig.sessionToken);
338
-
339
- // Encrypt keystore password via AES (128bit)
340
- let encryptedPwd = this._aesEncrypt(certData.ksPassword, md5Pass, iv);
341
-
342
- // Encode IV using Base64
343
- let encodedIv = this._b64Encode(iv);
344
-
345
- // Encode encrypted password using Base64
346
- let encodedPwd = this._b64Encode(encryptedPwd);
347
-
348
- //=================================================================
349
-
350
- // Set parameters to be sent with the certificate keystore file
351
- const params = new FormData();
352
- params.append('files[]', certData.file.rawFile);
353
- params.append('__iv', encodedIv);
354
- params.append('__password', encodedPwd);
355
- params.append('__module', this._uploadTargetConfig.moduleId);
356
-
357
- // Set destination url
358
- const url = this._uploadTargetConfig.protocol + '://' + this._uploadTargetConfig.host + ':' + this._uploadTargetConfig.port + '/BlueBox/SFS2XFileUpload?sessHashId=' + this._uploadTargetConfig.sessionToken;
359
-
360
- // Start upload
361
- fetch(url, {
362
- method: 'POST',
363
- body: params,
364
- mode: 'no-cors'
365
- }).then($.proxy(this._onSslCertUploadEnd, this));
366
- }
367
- }
368
-
369
- _onSslCertUploadEnd(response)
370
- {
371
- // Nothing to do: we have to wait the upload process completion to be signaled by the server through the dedicated Extension response
372
-
373
- //=================================================================
374
-
375
- // TODO Should we handle this response in some way? For some unknown reason we always get ok=false and status=0
376
- //console.log(response)
377
- //console.log(response.ok)
378
- //console.log(response.status)
379
- }
380
-
381
- /**
382
- * Method called by parent when upload failed.
383
- */
384
- onSslCertUploadError(error)
385
- {
386
- let modalElement = $('#uploadModal', $(this));
387
-
388
- if (modalElement)
389
- {
390
- // Enable modal
391
- this.enabled = true;
392
-
393
- // Show upload error
394
- $('#uploadErrorMsg', modalElement).show();
395
- $('#uploadErrorMsg', modalElement).text(error + '.');
396
-
397
- // Hide spinner
398
- $('#uploadSpinner', modalElement).hide();
399
- }
400
- }
401
-
402
- /**
403
- * Method called by parent when upload is completed successfully.
404
- */
405
- onSslCertUploadSuccess()
406
- {
407
- let modalElement = $('#uploadModal', $(this));
408
-
409
- if (modalElement)
410
- {
411
- // Enable modal
412
- this.enabled = true;
413
-
414
- // Hide spinner
415
- $('#uploadSpinner', modalElement).hide();
416
-
417
- // Hide modal
418
- modalElement.modal('hide');
419
- }
420
- }
421
-
422
- // *****************************************************************
423
-
424
- /*
425
- * Takes a string and returns the MD5 as Uint8Array
426
- */
427
- _binaryMD5(str)
428
- {
429
- let MD5 = new SFS2X.MD5();
430
- let hexStr = MD5.hex_md5(str);
431
-
432
- return this._hexByteStringToByteArray(hexStr);
433
- }
434
-
435
- /*
436
- * Hex bytes ---> Actual byte[] as Uint8Array
437
- */
438
- _hexByteStringToByteArray(hexByteString)
439
- {
440
- let bytes = new Uint8Array(16); // MD5 fixed output size
441
-
442
- for (let i = 0; i < hexByteString.length;)
443
- {
444
- let hexByte = hexByteString[i++] + hexByteString[i++];
445
- let byte = parseInt(hexByte, 16);
446
-
447
- bytes[i / 2 - 1] = byte;
448
- }
449
-
450
- return bytes;
451
- }
452
-
453
- /*
454
- * Encrypt using AES, mode CBC, PKCS#7 padding
455
- *
456
- * text -> the text we want to encode
457
- * key -> the AES key
458
- * iv -> the AES/CBC init vector
459
- *
460
- * Returns -> Uint8Array
461
- */
462
- _aesEncrypt(text, key, iv)
463
- {
464
- let textBytes = aes_js__WEBPACK_IMPORTED_MODULE_1___default.a.utils.utf8.toBytes(text); // Get UTF-8 bytes
465
- let aesCBC = new aes_js__WEBPACK_IMPORTED_MODULE_1___default.a.ModeOfOperation.cbc(key, iv); // Init CBC mode
466
- textBytes = aes_js__WEBPACK_IMPORTED_MODULE_1___default.a.padding.pkcs7.pad(textBytes); // PKCS#7 padding
467
-
468
- // Encrypt
469
- return aesCBC.encrypt(textBytes);
470
- }
471
-
472
- /*
473
- * Encode passed byte array --> Base64 representation
474
- * Returns --> string
475
- */
476
- _b64Encode(barray)
477
- {
478
- return btoa(String.fromCharCode.apply(null, barray));
4
+ /***/ "./node_modules/moment/locale sync recursive ^\\.\\/.*$":
5
+ /*!**************************************************!*\
6
+ !*** ./node_modules/moment/locale sync ^\.\/.*$ ***!
7
+ \**************************************************/
8
+ /*! no static exports found */
9
+ /***/ (function(module, exports, __webpack_require__) {
10
+
11
+ var map = {
12
+ "./af": "./node_modules/moment/locale/af.js",
13
+ "./af.js": "./node_modules/moment/locale/af.js",
14
+ "./ar": "./node_modules/moment/locale/ar.js",
15
+ "./ar-dz": "./node_modules/moment/locale/ar-dz.js",
16
+ "./ar-dz.js": "./node_modules/moment/locale/ar-dz.js",
17
+ "./ar-kw": "./node_modules/moment/locale/ar-kw.js",
18
+ "./ar-kw.js": "./node_modules/moment/locale/ar-kw.js",
19
+ "./ar-ly": "./node_modules/moment/locale/ar-ly.js",
20
+ "./ar-ly.js": "./node_modules/moment/locale/ar-ly.js",
21
+ "./ar-ma": "./node_modules/moment/locale/ar-ma.js",
22
+ "./ar-ma.js": "./node_modules/moment/locale/ar-ma.js",
23
+ "./ar-sa": "./node_modules/moment/locale/ar-sa.js",
24
+ "./ar-sa.js": "./node_modules/moment/locale/ar-sa.js",
25
+ "./ar-tn": "./node_modules/moment/locale/ar-tn.js",
26
+ "./ar-tn.js": "./node_modules/moment/locale/ar-tn.js",
27
+ "./ar.js": "./node_modules/moment/locale/ar.js",
28
+ "./az": "./node_modules/moment/locale/az.js",
29
+ "./az.js": "./node_modules/moment/locale/az.js",
30
+ "./be": "./node_modules/moment/locale/be.js",
31
+ "./be.js": "./node_modules/moment/locale/be.js",
32
+ "./bg": "./node_modules/moment/locale/bg.js",
33
+ "./bg.js": "./node_modules/moment/locale/bg.js",
34
+ "./bm": "./node_modules/moment/locale/bm.js",
35
+ "./bm.js": "./node_modules/moment/locale/bm.js",
36
+ "./bn": "./node_modules/moment/locale/bn.js",
37
+ "./bn.js": "./node_modules/moment/locale/bn.js",
38
+ "./bo": "./node_modules/moment/locale/bo.js",
39
+ "./bo.js": "./node_modules/moment/locale/bo.js",
40
+ "./br": "./node_modules/moment/locale/br.js",
41
+ "./br.js": "./node_modules/moment/locale/br.js",
42
+ "./bs": "./node_modules/moment/locale/bs.js",
43
+ "./bs.js": "./node_modules/moment/locale/bs.js",
44
+ "./ca": "./node_modules/moment/locale/ca.js",
45
+ "./ca.js": "./node_modules/moment/locale/ca.js",
46
+ "./cs": "./node_modules/moment/locale/cs.js",
47
+ "./cs.js": "./node_modules/moment/locale/cs.js",
48
+ "./cv": "./node_modules/moment/locale/cv.js",
49
+ "./cv.js": "./node_modules/moment/locale/cv.js",
50
+ "./cy": "./node_modules/moment/locale/cy.js",
51
+ "./cy.js": "./node_modules/moment/locale/cy.js",
52
+ "./da": "./node_modules/moment/locale/da.js",
53
+ "./da.js": "./node_modules/moment/locale/da.js",
54
+ "./de": "./node_modules/moment/locale/de.js",
55
+ "./de-at": "./node_modules/moment/locale/de-at.js",
56
+ "./de-at.js": "./node_modules/moment/locale/de-at.js",
57
+ "./de-ch": "./node_modules/moment/locale/de-ch.js",
58
+ "./de-ch.js": "./node_modules/moment/locale/de-ch.js",
59
+ "./de.js": "./node_modules/moment/locale/de.js",
60
+ "./dv": "./node_modules/moment/locale/dv.js",
61
+ "./dv.js": "./node_modules/moment/locale/dv.js",
62
+ "./el": "./node_modules/moment/locale/el.js",
63
+ "./el.js": "./node_modules/moment/locale/el.js",
64
+ "./en-SG": "./node_modules/moment/locale/en-SG.js",
65
+ "./en-SG.js": "./node_modules/moment/locale/en-SG.js",
66
+ "./en-au": "./node_modules/moment/locale/en-au.js",
67
+ "./en-au.js": "./node_modules/moment/locale/en-au.js",
68
+ "./en-ca": "./node_modules/moment/locale/en-ca.js",
69
+ "./en-ca.js": "./node_modules/moment/locale/en-ca.js",
70
+ "./en-gb": "./node_modules/moment/locale/en-gb.js",
71
+ "./en-gb.js": "./node_modules/moment/locale/en-gb.js",
72
+ "./en-ie": "./node_modules/moment/locale/en-ie.js",
73
+ "./en-ie.js": "./node_modules/moment/locale/en-ie.js",
74
+ "./en-il": "./node_modules/moment/locale/en-il.js",
75
+ "./en-il.js": "./node_modules/moment/locale/en-il.js",
76
+ "./en-nz": "./node_modules/moment/locale/en-nz.js",
77
+ "./en-nz.js": "./node_modules/moment/locale/en-nz.js",
78
+ "./eo": "./node_modules/moment/locale/eo.js",
79
+ "./eo.js": "./node_modules/moment/locale/eo.js",
80
+ "./es": "./node_modules/moment/locale/es.js",
81
+ "./es-do": "./node_modules/moment/locale/es-do.js",
82
+ "./es-do.js": "./node_modules/moment/locale/es-do.js",
83
+ "./es-us": "./node_modules/moment/locale/es-us.js",
84
+ "./es-us.js": "./node_modules/moment/locale/es-us.js",
85
+ "./es.js": "./node_modules/moment/locale/es.js",
86
+ "./et": "./node_modules/moment/locale/et.js",
87
+ "./et.js": "./node_modules/moment/locale/et.js",
88
+ "./eu": "./node_modules/moment/locale/eu.js",
89
+ "./eu.js": "./node_modules/moment/locale/eu.js",
90
+ "./fa": "./node_modules/moment/locale/fa.js",
91
+ "./fa.js": "./node_modules/moment/locale/fa.js",
92
+ "./fi": "./node_modules/moment/locale/fi.js",
93
+ "./fi.js": "./node_modules/moment/locale/fi.js",
94
+ "./fo": "./node_modules/moment/locale/fo.js",
95
+ "./fo.js": "./node_modules/moment/locale/fo.js",
96
+ "./fr": "./node_modules/moment/locale/fr.js",
97
+ "./fr-ca": "./node_modules/moment/locale/fr-ca.js",
98
+ "./fr-ca.js": "./node_modules/moment/locale/fr-ca.js",
99
+ "./fr-ch": "./node_modules/moment/locale/fr-ch.js",
100
+ "./fr-ch.js": "./node_modules/moment/locale/fr-ch.js",
101
+ "./fr.js": "./node_modules/moment/locale/fr.js",
102
+ "./fy": "./node_modules/moment/locale/fy.js",
103
+ "./fy.js": "./node_modules/moment/locale/fy.js",
104
+ "./ga": "./node_modules/moment/locale/ga.js",
105
+ "./ga.js": "./node_modules/moment/locale/ga.js",
106
+ "./gd": "./node_modules/moment/locale/gd.js",
107
+ "./gd.js": "./node_modules/moment/locale/gd.js",
108
+ "./gl": "./node_modules/moment/locale/gl.js",
109
+ "./gl.js": "./node_modules/moment/locale/gl.js",
110
+ "./gom-latn": "./node_modules/moment/locale/gom-latn.js",
111
+ "./gom-latn.js": "./node_modules/moment/locale/gom-latn.js",
112
+ "./gu": "./node_modules/moment/locale/gu.js",
113
+ "./gu.js": "./node_modules/moment/locale/gu.js",
114
+ "./he": "./node_modules/moment/locale/he.js",
115
+ "./he.js": "./node_modules/moment/locale/he.js",
116
+ "./hi": "./node_modules/moment/locale/hi.js",
117
+ "./hi.js": "./node_modules/moment/locale/hi.js",
118
+ "./hr": "./node_modules/moment/locale/hr.js",
119
+ "./hr.js": "./node_modules/moment/locale/hr.js",
120
+ "./hu": "./node_modules/moment/locale/hu.js",
121
+ "./hu.js": "./node_modules/moment/locale/hu.js",
122
+ "./hy-am": "./node_modules/moment/locale/hy-am.js",
123
+ "./hy-am.js": "./node_modules/moment/locale/hy-am.js",
124
+ "./id": "./node_modules/moment/locale/id.js",
125
+ "./id.js": "./node_modules/moment/locale/id.js",
126
+ "./is": "./node_modules/moment/locale/is.js",
127
+ "./is.js": "./node_modules/moment/locale/is.js",
128
+ "./it": "./node_modules/moment/locale/it.js",
129
+ "./it-ch": "./node_modules/moment/locale/it-ch.js",
130
+ "./it-ch.js": "./node_modules/moment/locale/it-ch.js",
131
+ "./it.js": "./node_modules/moment/locale/it.js",
132
+ "./ja": "./node_modules/moment/locale/ja.js",
133
+ "./ja.js": "./node_modules/moment/locale/ja.js",
134
+ "./jv": "./node_modules/moment/locale/jv.js",
135
+ "./jv.js": "./node_modules/moment/locale/jv.js",
136
+ "./ka": "./node_modules/moment/locale/ka.js",
137
+ "./ka.js": "./node_modules/moment/locale/ka.js",
138
+ "./kk": "./node_modules/moment/locale/kk.js",
139
+ "./kk.js": "./node_modules/moment/locale/kk.js",
140
+ "./km": "./node_modules/moment/locale/km.js",
141
+ "./km.js": "./node_modules/moment/locale/km.js",
142
+ "./kn": "./node_modules/moment/locale/kn.js",
143
+ "./kn.js": "./node_modules/moment/locale/kn.js",
144
+ "./ko": "./node_modules/moment/locale/ko.js",
145
+ "./ko.js": "./node_modules/moment/locale/ko.js",
146
+ "./ku": "./node_modules/moment/locale/ku.js",
147
+ "./ku.js": "./node_modules/moment/locale/ku.js",
148
+ "./ky": "./node_modules/moment/locale/ky.js",
149
+ "./ky.js": "./node_modules/moment/locale/ky.js",
150
+ "./lb": "./node_modules/moment/locale/lb.js",
151
+ "./lb.js": "./node_modules/moment/locale/lb.js",
152
+ "./lo": "./node_modules/moment/locale/lo.js",
153
+ "./lo.js": "./node_modules/moment/locale/lo.js",
154
+ "./lt": "./node_modules/moment/locale/lt.js",
155
+ "./lt.js": "./node_modules/moment/locale/lt.js",
156
+ "./lv": "./node_modules/moment/locale/lv.js",
157
+ "./lv.js": "./node_modules/moment/locale/lv.js",
158
+ "./me": "./node_modules/moment/locale/me.js",
159
+ "./me.js": "./node_modules/moment/locale/me.js",
160
+ "./mi": "./node_modules/moment/locale/mi.js",
161
+ "./mi.js": "./node_modules/moment/locale/mi.js",
162
+ "./mk": "./node_modules/moment/locale/mk.js",
163
+ "./mk.js": "./node_modules/moment/locale/mk.js",
164
+ "./ml": "./node_modules/moment/locale/ml.js",
165
+ "./ml.js": "./node_modules/moment/locale/ml.js",
166
+ "./mn": "./node_modules/moment/locale/mn.js",
167
+ "./mn.js": "./node_modules/moment/locale/mn.js",
168
+ "./mr": "./node_modules/moment/locale/mr.js",
169
+ "./mr.js": "./node_modules/moment/locale/mr.js",
170
+ "./ms": "./node_modules/moment/locale/ms.js",
171
+ "./ms-my": "./node_modules/moment/locale/ms-my.js",
172
+ "./ms-my.js": "./node_modules/moment/locale/ms-my.js",
173
+ "./ms.js": "./node_modules/moment/locale/ms.js",
174
+ "./mt": "./node_modules/moment/locale/mt.js",
175
+ "./mt.js": "./node_modules/moment/locale/mt.js",
176
+ "./my": "./node_modules/moment/locale/my.js",
177
+ "./my.js": "./node_modules/moment/locale/my.js",
178
+ "./nb": "./node_modules/moment/locale/nb.js",
179
+ "./nb.js": "./node_modules/moment/locale/nb.js",
180
+ "./ne": "./node_modules/moment/locale/ne.js",
181
+ "./ne.js": "./node_modules/moment/locale/ne.js",
182
+ "./nl": "./node_modules/moment/locale/nl.js",
183
+ "./nl-be": "./node_modules/moment/locale/nl-be.js",
184
+ "./nl-be.js": "./node_modules/moment/locale/nl-be.js",
185
+ "./nl.js": "./node_modules/moment/locale/nl.js",
186
+ "./nn": "./node_modules/moment/locale/nn.js",
187
+ "./nn.js": "./node_modules/moment/locale/nn.js",
188
+ "./pa-in": "./node_modules/moment/locale/pa-in.js",
189
+ "./pa-in.js": "./node_modules/moment/locale/pa-in.js",
190
+ "./pl": "./node_modules/moment/locale/pl.js",
191
+ "./pl.js": "./node_modules/moment/locale/pl.js",
192
+ "./pt": "./node_modules/moment/locale/pt.js",
193
+ "./pt-br": "./node_modules/moment/locale/pt-br.js",
194
+ "./pt-br.js": "./node_modules/moment/locale/pt-br.js",
195
+ "./pt.js": "./node_modules/moment/locale/pt.js",
196
+ "./ro": "./node_modules/moment/locale/ro.js",
197
+ "./ro.js": "./node_modules/moment/locale/ro.js",
198
+ "./ru": "./node_modules/moment/locale/ru.js",
199
+ "./ru.js": "./node_modules/moment/locale/ru.js",
200
+ "./sd": "./node_modules/moment/locale/sd.js",
201
+ "./sd.js": "./node_modules/moment/locale/sd.js",
202
+ "./se": "./node_modules/moment/locale/se.js",
203
+ "./se.js": "./node_modules/moment/locale/se.js",
204
+ "./si": "./node_modules/moment/locale/si.js",
205
+ "./si.js": "./node_modules/moment/locale/si.js",
206
+ "./sk": "./node_modules/moment/locale/sk.js",
207
+ "./sk.js": "./node_modules/moment/locale/sk.js",
208
+ "./sl": "./node_modules/moment/locale/sl.js",
209
+ "./sl.js": "./node_modules/moment/locale/sl.js",
210
+ "./sq": "./node_modules/moment/locale/sq.js",
211
+ "./sq.js": "./node_modules/moment/locale/sq.js",
212
+ "./sr": "./node_modules/moment/locale/sr.js",
213
+ "./sr-cyrl": "./node_modules/moment/locale/sr-cyrl.js",
214
+ "./sr-cyrl.js": "./node_modules/moment/locale/sr-cyrl.js",
215
+ "./sr.js": "./node_modules/moment/locale/sr.js",
216
+ "./ss": "./node_modules/moment/locale/ss.js",
217
+ "./ss.js": "./node_modules/moment/locale/ss.js",
218
+ "./sv": "./node_modules/moment/locale/sv.js",
219
+ "./sv.js": "./node_modules/moment/locale/sv.js",
220
+ "./sw": "./node_modules/moment/locale/sw.js",
221
+ "./sw.js": "./node_modules/moment/locale/sw.js",
222
+ "./ta": "./node_modules/moment/locale/ta.js",
223
+ "./ta.js": "./node_modules/moment/locale/ta.js",
224
+ "./te": "./node_modules/moment/locale/te.js",
225
+ "./te.js": "./node_modules/moment/locale/te.js",
226
+ "./tet": "./node_modules/moment/locale/tet.js",
227
+ "./tet.js": "./node_modules/moment/locale/tet.js",
228
+ "./tg": "./node_modules/moment/locale/tg.js",
229
+ "./tg.js": "./node_modules/moment/locale/tg.js",
230
+ "./th": "./node_modules/moment/locale/th.js",
231
+ "./th.js": "./node_modules/moment/locale/th.js",
232
+ "./tl-ph": "./node_modules/moment/locale/tl-ph.js",
233
+ "./tl-ph.js": "./node_modules/moment/locale/tl-ph.js",
234
+ "./tlh": "./node_modules/moment/locale/tlh.js",
235
+ "./tlh.js": "./node_modules/moment/locale/tlh.js",
236
+ "./tr": "./node_modules/moment/locale/tr.js",
237
+ "./tr.js": "./node_modules/moment/locale/tr.js",
238
+ "./tzl": "./node_modules/moment/locale/tzl.js",
239
+ "./tzl.js": "./node_modules/moment/locale/tzl.js",
240
+ "./tzm": "./node_modules/moment/locale/tzm.js",
241
+ "./tzm-latn": "./node_modules/moment/locale/tzm-latn.js",
242
+ "./tzm-latn.js": "./node_modules/moment/locale/tzm-latn.js",
243
+ "./tzm.js": "./node_modules/moment/locale/tzm.js",
244
+ "./ug-cn": "./node_modules/moment/locale/ug-cn.js",
245
+ "./ug-cn.js": "./node_modules/moment/locale/ug-cn.js",
246
+ "./uk": "./node_modules/moment/locale/uk.js",
247
+ "./uk.js": "./node_modules/moment/locale/uk.js",
248
+ "./ur": "./node_modules/moment/locale/ur.js",
249
+ "./ur.js": "./node_modules/moment/locale/ur.js",
250
+ "./uz": "./node_modules/moment/locale/uz.js",
251
+ "./uz-latn": "./node_modules/moment/locale/uz-latn.js",
252
+ "./uz-latn.js": "./node_modules/moment/locale/uz-latn.js",
253
+ "./uz.js": "./node_modules/moment/locale/uz.js",
254
+ "./vi": "./node_modules/moment/locale/vi.js",
255
+ "./vi.js": "./node_modules/moment/locale/vi.js",
256
+ "./x-pseudo": "./node_modules/moment/locale/x-pseudo.js",
257
+ "./x-pseudo.js": "./node_modules/moment/locale/x-pseudo.js",
258
+ "./yo": "./node_modules/moment/locale/yo.js",
259
+ "./yo.js": "./node_modules/moment/locale/yo.js",
260
+ "./zh-cn": "./node_modules/moment/locale/zh-cn.js",
261
+ "./zh-cn.js": "./node_modules/moment/locale/zh-cn.js",
262
+ "./zh-hk": "./node_modules/moment/locale/zh-hk.js",
263
+ "./zh-hk.js": "./node_modules/moment/locale/zh-hk.js",
264
+ "./zh-tw": "./node_modules/moment/locale/zh-tw.js",
265
+ "./zh-tw.js": "./node_modules/moment/locale/zh-tw.js"
266
+ };
267
+
268
+
269
+ function webpackContext(req) {
270
+ var id = webpackContextResolve(req);
271
+ return __webpack_require__(id);
272
+ }
273
+ function webpackContextResolve(req) {
274
+ if(!__webpack_require__.o(map, req)) {
275
+ var e = new Error("Cannot find module '" + req + "'");
276
+ e.code = 'MODULE_NOT_FOUND';
277
+ throw e;
479
278
  }
279
+ return map[req];
480
280
  }
481
-
482
- // DEFINE COMPONENT
483
- if (!window.customElements.get('ssl-certificate-manager'))
484
- window.customElements.define('ssl-certificate-manager', SslCertificateManager);
485
-
486
- /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
281
+ webpackContext.keys = function webpackContextKeys() {
282
+ return Object.keys(map);
283
+ };
284
+ webpackContext.resolve = webpackContextResolve;
285
+ module.exports = webpackContext;
286
+ webpackContext.id = "./node_modules/moment/locale sync recursive ^\\.\\/.*$";
487
287
 
488
288
  /***/ }),
489
289
 
490
- /***/ "./src/modules/server-configurator.js":
491
- /*!********************************************!*\
492
- !*** ./src/modules/server-configurator.js ***!
493
- \********************************************/
290
+ /***/ "./src/modules/extension-deployer.js":
291
+ /*!*******************************************!*\
292
+ !*** ./src/modules/extension-deployer.js ***!
293
+ \*******************************************/
494
294
  /*! exports provided: default */
495
295
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
496
296
 
497
297
  "use strict";
498
298
  __webpack_require__.r(__webpack_exports__);
499
- /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ServerConfigurator; });
299
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ExtensionDeployer; });
500
300
  /* harmony import */ var _base_module__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-module */ "./src/modules/base-module.js");
501
- /* harmony import */ var _utils_uibuilder_config_interface_builder__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/uibuilder/config-interface-builder */ "./src/utils/uibuilder/config-interface-builder.js");
502
- /* harmony import */ var _components_module_specific_ssl_certificate_manager__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../components/module-specific/ssl-certificate-manager */ "./src/components/module-specific/ssl-certificate-manager.js");
503
-
301
+ /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! moment */ "./node_modules/moment/moment.js");
302
+ /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_1__);
504
303
 
505
304
 
506
305
 
507
- class ServerConfigurator extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
306
+ class ExtensionDeployer extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
508
307
  {
509
308
  constructor()
510
309
  {
511
- super('serverConfig');
310
+ super('extDeployer');
512
311
 
513
312
  // Outgoing requests
514
313
  this.REQ_INIT = 'init';
515
- this.REQ_GET_CONFIG = 'getConfig';
516
- this.REQ_UPDATE_CONFIG = 'updConfig';
517
- this.REQ_UPDATE_GEO_DB = 'updGeoDb';
314
+ this.REQ_GET_NODES = 'getNodes';
518
315
 
519
316
  // Incoming responses
317
+ this.RESP_LOCKED = 'lock';
520
318
  this.RESP_INIT = 'init';
521
- this.RESP_CONFIG = 'config';
522
- this.RESP_CONFIG_UPDATE_CONFIRM = 'configUpdate';
523
- this.RESP_CONFIG_CHANGED_ALERT = 'configAlert';
524
- this.RESP_SSL_UPLOAD_ERROR = 'sslUploadError';
525
- this.RESP_SSL_UPLOAD_CONFIRM = 'sslUpload';
526
- this.RESP_UPDATE_GEO_DB = 'geoDbUpdate';
319
+ this.RESP_NODES = 'nodes';
320
+ this.RESP_SUCCESS = 'success';
321
+ this.RESP_WARN = 'warn';
322
+ this.RESP_ERROR = 'error';
323
+
324
+ this._selectedNodes = [];
527
325
  }
528
326
 
529
327
  //------------------------------------
530
328
  // COMMON MODULE INTERFACE METHODS
531
329
  // This members are used by the main controller
532
330
  // to communicate with the module's controller.
533
- // This methods override those in BaseModule class.
534
331
  //------------------------------------
535
332
 
536
333
  initialize(idData, shellController)
@@ -538,8 +335,8 @@ class ServerConfigurator extends _base_module__WEBPACK_IMPORTED_MODULE_0__["Base
538
335
  // Call super method
539
336
  super.initialize(idData, shellController);
540
337
 
541
- // Initialize progress bar
542
- $('#src-progressBar').kendoProgressBar({
338
+ // Initialize progress bars
339
+ $('.exd-progressBar').kendoProgressBar({
543
340
  min: 0,
544
341
  max: 100,
545
342
  value: false,
@@ -549,20 +346,103 @@ class ServerConfigurator extends _base_module__WEBPACK_IMPORTED_MODULE_0__["Base
549
346
  }
550
347
  });
551
348
 
552
- // Create interface builder instance
553
- this._interfaceBuilder = new _utils_uibuilder_config_interface_builder__WEBPACK_IMPORTED_MODULE_1__["ConfigInterfaceBuilder"]();
349
+ // Add listeners to buttons
350
+ $('#exd-retryBt').on('click', $.proxy(this._onRetryClick, this));
351
+ $('#exd-refreshBt').on('click', $.proxy(this._requestNodesList, this));
352
+ $('#exd-deployBt').on('click', $.proxy(this._onDeployClick, this));
353
+ $('.exd-statusCloseBt').on('click', $.proxy(this._onCloseStatusClick, this));
354
+
355
+ // Initialize kendo switch
356
+ this._modeSwitch = $('#exd-modeCb').kendoSwitch().data('kendoSwitch');
357
+
358
+ // Initialize grid
359
+ this._grid = $('#exd-nodesList').kendoGrid({
360
+ scrollable: true,
361
+ sortable: true,
362
+ //resizable: true,
363
+ selectable: false,
364
+ columns: [
365
+ {
366
+ selectable: true,
367
+ width: 41
368
+ },
369
+ {
370
+ field: 'name',
371
+ width: 500,
372
+ title: 'Node',
373
+ template: function(dataItem) {
374
+ if (dataItem['alias'])
375
+ return '<div class="name-cell"><span>' + dataItem['alias'] + '</span><br><small class="text-muted">' + dataItem['name'] + '<small></div>';
376
+ else
377
+ return '<div class="name-cell"><span>' + dataItem['name'] + '</span></div>';
378
+ }
379
+ },
380
+ {
381
+ field: 'health',
382
+ width: 75,
383
+ title: 'Health',
384
+ sortable: false,
385
+ template: $.proxy(this._getHealthTemplate, this)
386
+ },
387
+ ],
388
+ noRecords: {
389
+ template: 'No game nodes in the cluster.'
390
+ },
391
+ dataSource: {
392
+ schema: {
393
+ model: {
394
+ id: 'id',
395
+ // fields: {
396
+ // id: { type: 'string' },
397
+ // active: { type: 'boolean' }
398
+ // }
399
+ }
400
+ },
401
+ group: {
402
+ field: 'active',
403
+ dir: 'desc',
404
+ }
405
+ },
406
+ change: $.proxy(this._onNodesGridChange, this),
407
+ dataBound: $.proxy(this._onNodesGridDataBound, this),
408
+ }).data('kendoGrid');
409
+
410
+ // Initialize kendo uploader
411
+ this._uploader = $('#exd-uploader').kendoUpload({
412
+ multiple: false,
413
+ async: {
414
+ saveUrl: 'http://localhost', // This will be changed later in _onUploadStart method
415
+ autoUpload: false,
416
+ },
417
+ directoryDrop: true,
418
+ upload: $.proxy(this._onUploadStart, this),
419
+ complete: $.proxy(this._onUploadEnd, this),
420
+ localization: {
421
+ select: 'Select zip file...'
422
+ }
423
+ }).data('kendoUpload');
554
424
 
555
- // Add listener to GeoLite2 database update button
556
- $('#src-updateGeolocDbButton').on('click', $.proxy(this._onUpdateGeolocDbClick, this));
425
+ // Initialize "deployment status" modal
426
+ this._deployStatusModal = $('#exd-deployStatusModal');
427
+ this._deployStatusModal.modal({
428
+ backdrop: 'static',
429
+ keyboard: false,
430
+ show: false
431
+ });
557
432
 
558
- // Add listener to interface buttons
559
- $('#src-reloadButton').on('click', $.proxy(this._onReloadClick, this));
560
- $('#src-submitButton').on('click', $.proxy(this._onSubmitClick, this));
433
+ // Initialize help tooltips
434
+ $(this).kendoTooltip({
435
+ filter: 'i[title].help',
436
+ position: 'right',
437
+ content: function(e) {
438
+ return `<div class="help-tooltip">${e.target.data('title')}</div>`;
439
+ }
440
+ });
561
441
 
562
- // Save ref to SSL Manager
563
- this._sslCertManager = document.getElementById('src-sslCertManager');
442
+ // Set upload form disabled
443
+ this._enableDeployForm(false);
564
444
 
565
- //-----------------------------------*/
445
+ //-------------------------------------------
566
446
 
567
447
  // Send initialization request
568
448
  this.sendExtensionRequest(this.REQ_INIT);
@@ -573,28 +453,38 @@ class ServerConfigurator extends _base_module__WEBPACK_IMPORTED_MODULE_0__["Base
573
453
  // Call super method
574
454
  super.destroy();
575
455
 
576
- // Destroy SSL Certificate Manager
577
- this._sslCertManager.destroy();
456
+ // Remove click listeners
457
+ $('#exd-retryBt').off('click');
458
+ $('#exd-refreshBt').off('click');
459
+ $('#exd-deployBt').off('click');
460
+ $('.exd-statusCloseBt').off('click');
578
461
 
579
- // Remove interface buttons click listeners
580
- $('#src-updateGeolocDbButton').off('click');
581
- $('#src-reloadButton').off('click');
582
- $('#src-submitButton').off('click');
583
-
584
- // Clear tabs container
585
- this._clearTabs();
462
+ // Clear nodes request scheduling
463
+ clearTimeout(this._requestNodesTimer);
586
464
  }
587
465
 
588
466
  onExtensionCommand(command, data)
589
467
  {
590
- // Initialization data received
591
- if (command == this.RESP_INIT)
468
+ /*
469
+ * This response is returned if the file UploadsLock.txt exists in the /config folder of the server.
470
+ * This is an additional security measure to avoid unwanted files to be uploaded by malicius users accessing the server
471
+ * with the default credentials, in case they have not been changed by the administrator after the installation.
472
+ * The file must be removed manually before accessing the Extension Deployer module for the first time
473
+ */
474
+ if (command == this.RESP_LOCKED)
475
+ {
476
+ // Show warning
477
+ this._switchMainView('exd-locked');
478
+ }
479
+
480
+ // Module can be enabled (no locking file exists)
481
+ else if (command == this.RESP_INIT)
592
482
  {
593
483
  // Retrieve module id sent by the server (required because multiple modules use file uploading service)
594
484
  const uploadModuleId = data.getUtfString('modId');
595
485
 
596
- // Set SSL upload manager target configuration
597
- this._sslCertManager.uploadTargetConfig = {
486
+ // Set file uploading target configuration
487
+ this._uploadTargetConfig = {
598
488
  sessionToken: this.smartFox.sessionToken,
599
489
  host: this.smartFox.config.host,
600
490
  port: this.smartFox.config.port,
@@ -602,239 +492,272 @@ class ServerConfigurator extends _base_module__WEBPACK_IMPORTED_MODULE_0__["Base
602
492
  protocol: this.smartFox.config.useSSL ? 'https' : 'http'
603
493
  };
604
494
 
605
- // Server sends a flag indicating if file uploads are locked
606
- // We use it to enable the "Manage SSL certificate" button
607
- this._sslLocked = data.getBool('lock');
608
-
609
- if (!this._sslLocked)
610
- $('#src-manageSslWarn').hide();
495
+ // Show module's main view
496
+ this._switchMainView('exd-main');
611
497
 
612
- // Request configuration data to server instance
613
- this.sendExtensionRequest(this.REQ_GET_CONFIG);
498
+ // Request nodes list to server
499
+ this._requestNodesList();
614
500
  }
615
501
 
616
- // Server configuration data received
617
- else if (command == this.RESP_CONFIG)
502
+ else if (command == this.RESP_NODES)
618
503
  {
619
- // Build user interface based on received data
620
- this._interfaceBuilder.buildInterface(data.getSFSArray('settings'), 'src-tabNavigator', false);
504
+ let nodesObj = data.getSFSArray('nodes');
621
505
 
622
- // Enable buttons
623
- this._enableButtons(true);
506
+ let nodes = [];
507
+ let nodesIds = [];
624
508
 
625
- // Initialize TabNavigator-ralated widgets
626
- if (!this._tabNavInitialized)
509
+ for (let i = 0; i < nodesObj.size(); i++)
627
510
  {
628
- // Enable scrolling tabs
629
- $('#src-tabNavigator > #tabs').scrollingTabs({
630
- bootstrapVersion: 4,
631
- scrollToTabEdge: true,
632
- enableSwiping: true,
633
- disableScrollArrowsOnFullyScrolled: true,
634
- cssClassLeftArrow: 'fa fa-chevron-left',
635
- cssClassRightArrow: 'fa fa-chevron-right'
636
- });
511
+ let node = nodesObj.getSFSArray(i);
512
+
513
+ nodesIds.push(node.getUtfString(0));
637
514
 
638
- this._tabNavInitialized = true;
515
+ nodes.push({
516
+ 'id': node.getUtfString(0),
517
+ 'alias': node.getUtfString(1),
518
+ 'name': node.getUtfString(2),
519
+ 'health': node.getBool(3),
520
+ 'active': node.getBool(4), // Used for grouping
521
+ });
639
522
  }
640
523
 
641
- // Run validation (to remove validation messages if data was reloaded)
642
- this._interfaceBuilder.checkIsValid();
524
+ // Get nodes grid datasource
525
+ let ds = this._grid.dataSource;
643
526
 
644
- this._switchView('src-main');
645
- }
527
+ // --- REMOVE NODES ---
646
528
 
647
- // Server configuration update confirmation
648
- else if (command == this.RESP_CONFIG_UPDATE_CONFIRM)
649
- {
650
- // Enable buttons
651
- this._enableButtons(true);
529
+ let self = this;
530
+ $.map(ds.data(), function (dataItem, index) {
531
+ if (dataItem && !nodesIds.includes(dataItem['id']))
532
+ {
533
+ // Remove node from datastore
534
+ ds.remove(dataItem);
652
535
 
653
- // Enable form items
654
- this._interfaceBuilder.disableInterface(false);
536
+ // Remove node from list of selected nodes (if selected)
537
+ self._selectedNodes = self._selectedNodes.filter(x => x !== dataItem['id']);
538
+ }
539
+ });
655
540
 
656
- // If the current user is the updater, show a notification
657
- // Otherwise, show a dialog box suggesting to reload
658
- let updater = data.getUtfString('user');
541
+ // --- ADD/UPDATE NODES ---
659
542
 
660
- if (updater == this.smartFox.mySelf.name)
543
+ for (let node of nodes)
661
544
  {
662
- // Reset the 'modified' flag
663
- this._interfaceBuilder.resetIsModified();
545
+ var dataItem = ds.get(node.id);
664
546
 
665
- // Display notification
666
- this.shellCtrl.showNotification('Server settings updated', 'Changes will be applied on next server restart');
667
- }
668
- else
669
- {
670
- // Show alert
671
- this.shellCtrl.showSimpleAlert(`Administrator ${updater} has modified the server settings; please reload to update your view.`);
547
+ // Update node
548
+ if (dataItem)
549
+ {
550
+ dataItem.set('health', node.health);
551
+ dataItem.set('active', node.active);
552
+
553
+ dataItem.dirty = false; // Hides "dirty" indicator in grid
554
+ }
672
555
 
673
- // Disable submit button
674
- $('#src-submitButton').attr('disabled', true);
556
+ // Add node
557
+ else
558
+ ds.add(node);
675
559
  }
560
+
561
+ // Refresh grid
562
+ this._grid.refresh();
676
563
  }
677
564
 
678
- // Server configuration xml saved by an external process
679
- else if (command == this.RESP_CONFIG_CHANGED_ALERT)
565
+ else if (command == this.RESP_ERROR)
680
566
  {
681
- // Show alert
682
- this.shellCtrl.showSimpleAlert(`The system has modified the server settings automatically; please reload to update your view.`);
567
+ // Display error message
568
+ $('#exd-statusErrorText').html(data.getUtfString('msg'));
683
569
 
684
- // Disable submit button
685
- $('#src-submitButton').attr('disabled', true);
570
+ // Switch to view
571
+ this._switchStatusView('exd-statusError');
686
572
  }
687
573
 
688
- // SSL certificate upload error
689
- else if (command == this.RESP_SSL_UPLOAD_ERROR)
574
+ else if (command == this.RESP_WARN)
690
575
  {
691
- const error = data.getUtfString('error');
692
-
693
- // Log warning
694
- this.shellCtrl.logMessage(error, 'error');
576
+ // Display error message
577
+ $('#exd-statusWarningText').html(data.getUtfString('msg').replace(/(?:\r\n|\r|\n)/g, '<br>'));
695
578
 
696
- // Show error in manager window
697
- this._sslCertManager.onSslCertUploadError(error);
579
+ // Switch to view
580
+ this._switchStatusView('exd-statusWarning');
698
581
  }
699
582
 
700
- // SSL certificate upload confirmed
701
- else if (command == this.RESP_SSL_UPLOAD_CONFIRM)
583
+ else if (command == this.RESP_SUCCESS)
702
584
  {
703
- // Closw manager window
704
- this._sslCertManager.onSslCertUploadSuccess();
705
-
706
- let updater = data.getUtfString('user');
707
-
708
- // Display notification
709
- if (updater == this.smartFox.mySelf.name)
710
- this.shellCtrl.showNotification('SSL certificate', 'SSL certificate keystore was uploaded successfully');
711
- else
712
- this.shellCtrl.showNotification('SSL certificate', `Administrator ${updater} has uploaded a new SSL certificate keystore`);
713
-
714
- // When a certificate is uploaded, HTTPS is also enabled automatically:
715
- // we have to update the interface accordingly
716
- this._updateConfigFormItemDisplayedValue('webServer.enableHttps', true);
585
+ this._switchStatusView('exd-statusSuccess');
717
586
  }
587
+ }
718
588
 
719
- // Geolocation database update confirmation
720
- else if (command == this.RESP_UPDATE_GEO_DB)
721
- {
722
- // Enable button
723
- $('#src-updateGeolocDbButton').attr('disabled', false);
589
+ //---------------------------------
590
+ // UI EVENT LISTENERS
591
+ //---------------------------------
724
592
 
725
- // Check success
726
- if (data.getBool('success'))
727
- {
728
- // Update displayed date
729
- this._updateConfigFormItemDisplayedValue('adminHelper.geoDbReleaseDate', data.getUtfString('newRelDate'));
593
+ _enableDeployForm(enabled)
594
+ {
595
+ $('#exd-uploadFileForm').prop('disabled', !enabled);
596
+ this._modeSwitch.enable(enabled);
597
+ }
730
598
 
731
- // If the current user is the updater, also show a notification
732
- let updater = data.getUtfString('user');
599
+ _onRetryClick()
600
+ {
601
+ this._switchMainView('exd-init');
733
602
 
734
- if (updater == this.smartFox.mySelf.name)
735
- this.shellCtrl.showNotification('Geolocation database updated', 'Latest release of the GeoLite2 Country database has been installed successfully');
736
- }
737
- else
738
- {
739
- // Show alert
740
- this.shellCtrl.showSimpleAlert(data.getUtfString('error'));
741
- }
742
- }
603
+ // Re-send initialization request
604
+ this.sendExtensionRequest(this.REQ_INIT);
743
605
  }
744
606
 
745
- //------------------------------------
746
- // PRIVATE METHODS
747
- //------------------------------------
607
+ _onCloseStatusClick()
608
+ {
609
+ this._deployStatusModal.hide();
610
+
611
+ // Clear uploader
612
+ this._uploader.clearAllFiles();
613
+ }
748
614
 
749
- _enableButtons(enabled)
615
+ _onNodesGridChange(e, args)
750
616
  {
751
- $('#src-reloadButton').attr('disabled', !enabled);
752
- $('#src-submitButton').attr('disabled', !enabled);
753
- $('#src-backupCheck').attr('disabled', !enabled);
617
+ let grid = e.sender;
618
+ let items = grid.items();
754
619
 
755
- $('#src-updateGeolocDbButton').attr('disabled', !enabled);
620
+ this._selectedNodes = [];
621
+
622
+ for (let i of grid.select())
623
+ {
624
+ let dataItem = grid.dataItem(i);
625
+ this._selectedNodes.push(dataItem['id']);
626
+ }
756
627
 
757
- if (!this._sslLocked)
758
- this._sslCertManager.enabled = enabled;
628
+ // Enable upload button
629
+ this._enableDeployForm(this._selectedNodes.length > 0);
759
630
  }
760
631
 
761
- _switchView(viewId)
632
+ _onNodesGridDataBound(e)
762
633
  {
763
- document.getElementById('src-viewstack').selectedElement = document.getElementById(viewId);
634
+ let grid = e.sender;
635
+ let items = grid.items();
636
+ let itemsToSelect = [];
637
+ let self = this;
638
+
639
+ items.each(function (idx, row) {
640
+ let dataItem = grid.dataItem(row);
641
+ if (self._selectedNodes.includes(dataItem['id'])) {
642
+ itemsToSelect.push(row);
643
+ }
644
+ });
645
+
646
+ // Re-select previously selected nodes
647
+ grid.select(itemsToSelect);
648
+
649
+ // Disable upload button
650
+ if (itemsToSelect.length == 0)
651
+ this._enableDeployForm(false);
652
+
653
+ //==================================================
654
+
655
+ // Hide group column and collapse icon
656
+ $('#exd-nodesList .k-group-col, #exd-nodesList .k-group-cell').remove();
657
+ let spanCells = $('#exd-nodesList .k-grouping-row').children('td');
658
+ spanCells.attr('colspan', spanCells.attr('colspan') - 1);
659
+ $('#exd-nodesList .k-icon.k-i-collapse').hide();
660
+
661
+ // Modify group label
662
+ $('#exd-nodesList .k-grouping-row td p.k-reset').each(function( index ) {
663
+ if ($(this).text() == 'active: true')
664
+ $(this).text('Active nodes');
665
+ else
666
+ $(this).text('Inactive nodes');
667
+ });
764
668
  }
765
669
 
766
- _clearTabs()
670
+ _requestNodesList()
767
671
  {
768
- // Destroy scrolling tabs
769
- $('#src-tabNavigator #tabs').scrollingTabs('destroy');
672
+ // Clear previous request scheduling
673
+ clearTimeout(this._requestNodesTimer);
674
+
675
+ // Check if connection is still available
676
+ if (this.smartFox.isConnected)
677
+ {
678
+ // Send request to extension
679
+ this.sendExtensionRequest(this.REQ_GET_NODES);
770
680
 
771
- // Remove all tab navigator content
772
- this._interfaceBuilder.destroyInterface();
681
+ // Schedule next request
682
+ this._requestNodesTimer = setTimeout($.proxy(this._requestNodesList, this), 5000); // Every 5 seconds
683
+ }
773
684
  }
774
685
 
775
- _onUpdateGeolocDbClick()
686
+ _onDeployClick()
776
687
  {
777
- // Disable button
778
- $('#src-updateGeolocDbButton').attr('disabled', true);
779
-
780
- // Send request to server
781
- this.sendExtensionRequest(this.REQ_UPDATE_GEO_DB);
688
+ // Trigger click on Upload widget
689
+ $('button.k-upload-selected').click();
782
690
  }
783
691
 
784
- _onReloadClick()
692
+ _onUploadStart(e)
785
693
  {
786
- // Disable buttons
787
- this._enableButtons(false);
694
+ // Display status modal
695
+ this._switchStatusView('exd-statusProgress');
696
+ this._deployStatusModal.show();
697
+
698
+ // Set destination url
699
+ const url = this._uploadTargetConfig.protocol + '://' + this._uploadTargetConfig.host + ':' + this._uploadTargetConfig.port + '/BlueBox/SFS2XFileUpload?sessHashId=' + this._uploadTargetConfig.sessionToken;
700
+
701
+ e.sender.options.async.saveUrl = url;
788
702
 
789
- // Switch to loading view
790
- this._switchView('src-loading');
703
+ // Set payload
704
+ const params = new FormData();
705
+ params.append('__module', this._uploadTargetConfig.moduleId);
706
+ params.append('__nodes', JSON.stringify(this._selectedNodes));
707
+ params.append('__noDestroy', this._modeSwitch.check());
791
708
 
792
- // Hide validation messages
793
- this._interfaceBuilder.resetValidation();
709
+ for (let f = 0; f < e.files.length; f++)
710
+ params.append('files[]', e.files[f].rawFile);
794
711
 
795
- // Request configuration data to server instance
796
- this.sendExtensionRequest(this.REQ_GET_CONFIG);
712
+ e.formData = params;
797
713
  }
798
714
 
799
- _onSubmitClick()
715
+ _onUploadEnd(e)
800
716
  {
801
- // Check validity
802
- if (this._interfaceBuilder.checkIsValid())
803
- {
804
- let changes = this._interfaceBuilder.getChangedData();
717
+ // Nothign to do
718
+ }
805
719
 
806
- if (changes.size() > 0)
807
- {
808
- // Disable buttons
809
- this._enableButtons(false);
720
+ _onFilesUploadEnd(response)
721
+ {
722
+ // Nothing to do: we have to wait the upload process completion to be signaled by the server through the dedicated Extension response
810
723
 
811
- // Disable form items
812
- this._interfaceBuilder.disableInterface(true);
724
+ //=================================================================
813
725
 
814
- // Send updated settings to server instance
815
- let params = new SFS2X.SFSObject();
816
- params.putSFSArray('settings', changes);
817
- params.putBool('backup', $('#src-backupCheck').prop('checked'));
726
+ // TODO Should we handle this response in some way? For some unknown reason we always get ok=false and status=0
727
+ // console.log(response)
728
+ // console.log(response.ok)
729
+ // console.log(response.status)
730
+ }
818
731
 
819
- this.sendExtensionRequest(this.REQ_UPDATE_CONFIG, params);
820
- }
821
- }
822
- else
823
- this.shellCtrl.showSimpleAlert('Unable to submit configuration changes due to an invalid value; please verify the highlighted form fields in all tabs.', true);
732
+ //------------------------------------
733
+ // PRIVATE METHODS
734
+ //------------------------------------
735
+
736
+ _switchMainView(viewId)
737
+ {
738
+ document.getElementById('exd-viewstack').selectedElement = document.getElementById(viewId);
739
+ }
740
+
741
+ _switchStatusView(viewId)
742
+ {
743
+ document.getElementById('exd-deployStatus').selectedElement = document.getElementById(viewId);
824
744
  }
825
745
 
826
- _updateConfigFormItemDisplayedValue(configParamName, newValue)
746
+ _getHealthTemplate(dataItem)
827
747
  {
828
- // Get the relevant Configuration Form Item
829
- const configFormItem = this._interfaceBuilder.getConfigFormItem(configParamName);
748
+ let style = 'text-success';
830
749
 
831
- // Update Configuration Parameter associated with the Configuration Form Item
832
- configFormItem.data.value = newValue;
833
- configFormItem.data.resetIsModified(); // This is needed to avoid the Configuration Parameter to flagged as 'changed'
750
+ if (!dataItem['health'])
751
+ style = 'text-danger';
834
752
 
835
- // Display the new value of the Configuration Form Item
836
- configFormItem._setWidgetValue(); // Display the new value in the config form item
753
+ return `<span class="${style}"><i class="fas fa-circle"></i></span>`;
837
754
  }
755
+
756
+ //---------------------------------
757
+ // PRIVATE GETTERS
758
+ //---------------------------------
759
+
760
+
838
761
  }
839
762
 
840
763
  /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
@@ -842,4 +765,4 @@ class ServerConfigurator extends _base_module__WEBPACK_IMPORTED_MODULE_0__["Base
842
765
  /***/ })
843
766
 
844
767
  }]);
845
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtOS5idW5kbGUuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL21vZHVsZS1zcGVjaWZpYy9zc2wtY2VydGlmaWNhdGUtbWFuYWdlci5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9tb2R1bGVzL3NlcnZlci1jb25maWd1cmF0b3IuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtieXRlc1RvU2l6ZX0gZnJvbSAnLi4vLi4vdXRpbHMvdXRpbGl0aWVzJztcbmltcG9ydCBhZXNqcyBmcm9tICdhZXMtanMnO1xuXG5leHBvcnQgY2xhc3MgU3NsQ2VydGlmaWNhdGVNYW5hZ2VyIGV4dGVuZHMgSFRNTEVsZW1lbnRcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdCAgICBzdXBlcigpO1xuXG5cdFx0dGhpcy5fbW9kYWxIdG1sID0gYFxuXHRcdFx0PGRpdiBjbGFzcz1cIm1vZGFsXCIgaWQ9XCJ1cGxvYWRNb2RhbFwiIHRhYmluZGV4PVwiLTFcIiByb2xlPVwiZGlhbG9nXCIgYXJpYS1sYWJlbGxlZGJ5PVwidXBsb2FkTW9kYWxUaXRsZVwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPlxuXHRcdFx0XHQ8ZGl2IGNsYXNzPVwibW9kYWwtZGlhbG9nIG1vZGFsLWRpYWxvZy1jZW50ZXJlZFwiIHJvbGU9XCJkb2N1bWVudFwiPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1jb250ZW50XCI+XG5cdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwibW9kYWwtaGVhZGVyXCI+XG5cdFx0XHRcdFx0XHRcdDxoNSBjbGFzcz1cIm1vZGFsLXRpdGxlIHRleHQtcHJpbWFyeVwiIGlkPVwidXBsb2FkTW9kYWxUaXRsZVwiPlNTTCBDZXJ0aWZpY2F0ZSBNYW5hZ2VyPC9oNT5cblx0XHRcdFx0XHRcdFx0PGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJjbG9zZVwiIGRhdGEtZGlzbWlzcz1cIm1vZGFsXCIgYXJpYS1sYWJlbD1cIkNsb3NlXCI+XG5cdFx0XHRcdFx0XHRcdFx0PHNwYW4gYXJpYS1oaWRkZW49XCJ0cnVlXCI+JnRpbWVzOzwvc3Bhbj5cblx0XHRcdFx0XHRcdFx0PC9idXR0b24+XG5cdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1ib2R5IGluLWZsb3ctaW52YWxpZC1tc2dcIj5cblx0XHRcdFx0XHRcdFx0PGZpZWxkc2V0IGlkPVwidXBsb2FkRmllbGRzZXRcIj5cblx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGlkPVwidXBsb2FkZXJTdWJmb3JtXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZm9ybS1ncm91cFwiPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiY29sLWZvcm0tbGFiZWwgZm9ybS1sYWJlbC1jb250YWluZXJcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8bGFiZWwgZm9yPVwidXBsb2FkZXJcIiBjbGFzcz1cImZvcm0tbGFiZWxcIj5DZXJ0aWZpY2F0ZSBrZXlzdG9yZSAoamtzKSA8aSBjbGFzcz1cImZhcyBmYS1xdWVzdGlvbi1jaXJjbGUgdGV4dC1tdXRlZCBoZWxwXCIgdGl0bGU9XCJTU0wgY2VydGlmaWNhdGUncyBwcm90ZWN0ZWQga2V5c3RvcmUgZmlsZSB0byBiZSB1cGxvYWRlZCB0byB0aGUgc2VydmVyLCBpbiBqa3MgZm9ybWF0XCI+PC9pPjwvbGFiZWw+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiaW5uZXItd2lkZ2V0XCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0PGlucHV0IHR5cGU9XCJmaWxlXCIgaWQ9XCJ1cGxvYWRlclwiIG5hbWU9XCJ1cGxvYWRlclwiIGFjY2VwdD1cIi5qa3NcIiBkYXRhLXVwbG9hZC1tc2c9XCJTZWxlY3QgYSBmaWxlXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJrLWludmFsaWQtbXNnIHBvc2l0aW9uLXN0YXRpY1wiIGRhdGEtZm9yPVwidXBsb2FkZXJcIj48L3NwYW4+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdFx0PGRpdiBpZD1cInBhc3N3b3Jkc1N1YmZvcm1cIj5cblx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJmb3JtLXJvd1wiPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZm9ybS1ncm91cCBjb2xcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiY29sLWZvcm0tbGFiZWwgZm9ybS1sYWJlbC1jb250YWluZXJcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdDxsYWJlbCBmb3I9XCJrc1Bhc3N3b3JkXCIgY2xhc3M9XCJmb3JtLWxhYmVsXCI+S2V5c3RvcmUgcGFzc3dvcmQgPGkgY2xhc3M9XCJmYXMgZmEtcXVlc3Rpb24tY2lyY2xlIHRleHQtbXV0ZWQgaGVscFwiIHRpdGxlPVwiUGFzc3dvcmQgdXNlZCB0byBwcm90ZWN0IHRoZSBjZXJ0aWZpY2F0ZSBrZXlzdG9yZVwiPjwvaT48L2xhYmVsPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJpbm5lci13aWRnZXRcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdDxpbnB1dCB0eXBlPVwicGFzc3dvcmRcIiBpZD1cImtzUGFzc3dvcmRcIiBuYW1lPVwia3NQYXNzd29yZFwiIGNsYXNzPVwiZm9ybS1jb250cm9sIGstdGV4dGJveFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIHJlcXVpcmVkIGRhdGEtcmVxdWlyZWQtbXNnPVwiUmVxdWlyZWRcIiAvPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJrLWludmFsaWQtbXNnIHBvc2l0aW9uLXN0YXRpY1wiIGRhdGEtZm9yPVwia3NQYXNzd29yZFwiPjwvc3Bhbj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImZvcm0tZ3JvdXAgY29sXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImNvbC1mb3JtLWxhYmVsIGZvcm0tbGFiZWwtY29udGFpbmVyXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8bGFiZWwgZm9yPVwiY29uZmlybUtzUGFzc3dvcmRcIiBjbGFzcz1cImZvcm0tbGFiZWxcIj5Db25maXJtIHBhc3N3b3JkIDxpIGNsYXNzPVwiZmFzIGZhLXF1ZXN0aW9uLWNpcmNsZSB0ZXh0LW11dGVkIGhlbHBcIiB0aXRsZT1cIktleXN0b3JlIHBhc3N3b3JkIGNvbmZpcm1hdGlvblwiPjwvaT48L2xhYmVsPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJpbm5lci13aWRnZXRcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdDxpbnB1dCB0eXBlPVwicGFzc3dvcmRcIiBpZD1cImNvbmZpcm1Lc1Bhc3N3b3JkXCIgbmFtZT1cImNvbmZpcm1Lc1Bhc3N3b3JkXCIgY2xhc3M9XCJmb3JtLWNvbnRyb2wgay10ZXh0Ym94XCIgYXV0b2NvbXBsZXRlPVwib2ZmXCIgcmVxdWlyZWQgZGF0YS1yZXF1aXJlZC1tc2c9XCJSZXF1aXJlZFwiIC8+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8c3BhbiBjbGFzcz1cImstaW52YWxpZC1tc2cgcG9zaXRpb24tc3RhdGljXCIgZGF0YS1mb3I9XCJjb25maXJtS3NQYXNzd29yZFwiPjwvc3Bhbj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblxuXHRcdFx0XHRcdFx0XHRcdFx0PHA+PGVtPkZvciBhZGRpdGlvbmFsIHNlY3VyaXR5LCBlbnRlciBhZ2FpbiBhbmQgY29uZmlybSB5b3VyIFNGUzJYIGFkbWluaXN0cmF0aW9uIHBhc3N3b3JkLjwvZW0+PC9wPlxuXG5cdFx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImZvcm0tZ3JvdXAgY29sXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImNvbC1mb3JtLWxhYmVsIGZvcm0tbGFiZWwtY29udGFpbmVyXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8bGFiZWwgZm9yPVwiYWRtaW5QYXNzd29yZFwiIGNsYXNzPVwiZm9ybS1sYWJlbFwiPkFkbWluIHBhc3N3b3JkIDxpIGNsYXNzPVwiZmFzIGZhLXF1ZXN0aW9uLWNpcmNsZSB0ZXh0LW11dGVkIGhlbHBcIiB0aXRsZT1cIlNtYXJ0Rm94U2VydmVyIDJYIHJlbW90ZSBhZG1pbmlzdHJhdGlvbiBwYXNzd29yZFwiPjwvaT48L2xhYmVsPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJpbm5lci13aWRnZXRcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdDxpbnB1dCB0eXBlPVwicGFzc3dvcmRcIiBpZD1cImFkbWluUGFzc3dvcmRcIiBuYW1lPVwiYWRtaW5QYXNzd29yZFwiIGNsYXNzPVwiZm9ybS1jb250cm9sIGstdGV4dGJveFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIHJlcXVpcmVkIGRhdGEtcmVxdWlyZWQtbXNnPVwiUmVxdWlyZWRcIiAvPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJrLWludmFsaWQtbXNnIHBvc2l0aW9uLXN0YXRpY1wiIGRhdGEtZm9yPVwiYWRtaW5QYXNzd29yZFwiPjwvc3Bhbj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImZvcm0tZ3JvdXAgY29sXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImNvbC1mb3JtLWxhYmVsIGZvcm0tbGFiZWwtY29udGFpbmVyXCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8bGFiZWwgZm9yPVwiY29uZmlybUFkbWluUGFzc3dvcmRcIiBjbGFzcz1cImZvcm0tbGFiZWxcIj5Db25maXJtIHBhc3N3b3JkIDxpIGNsYXNzPVwiZmFzIGZhLXF1ZXN0aW9uLWNpcmNsZSB0ZXh0LW11dGVkIGhlbHBcIiB0aXRsZT1cIlNtYXJ0Rm94U2VydmVyIDJYIHJlbW90ZSBhZG1pbmlzdHJhdGlvbiBwYXNzd29yZCBjb25maXJtYXRpb25cIj48L2k+PC9sYWJlbD5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiaW5uZXItd2lkZ2V0XCI+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQ8aW5wdXQgdHlwZT1cInBhc3N3b3JkXCIgaWQ9XCJjb25maXJtQWRtaW5QYXNzd29yZFwiIG5hbWU9XCJjb25maXJtQWRtaW5QYXNzd29yZFwiIGNsYXNzPVwiZm9ybS1jb250cm9sIGstdGV4dGJveFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiIHJlcXVpcmVkIGRhdGEtcmVxdWlyZWQtbXNnPVwiUmVxdWlyZWRcIiAvPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0PHNwYW4gY2xhc3M9XCJrLWludmFsaWQtbXNnIHBvc2l0aW9uLXN0YXRpY1wiIGRhdGEtZm9yPVwiY29uZmlybUFkbWluUGFzc3dvcmRcIj48L3NwYW4+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdDwvZmllbGRzZXQ+XG5cdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXIgZmxleC1jb2x1bW5cIj5cblx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImQtZmxleCB3LTEwMFwiPlxuXHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJmbGV4LWdyb3ctMSB0ZXh0LWxlZnRcIj5cblx0XHRcdFx0XHRcdFx0XHRcdDxidXR0b24gaWQ9XCJ1cGxvYWRTc2xCdXR0b25cIiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJrLWJ1dHRvbiBrLXByaW1hcnlcIj48aSBjbGFzcz1cImZhcyBmYS11cGxvYWQgbXItMVwiPjwvaT5VcGxvYWQgY2VydGlmaWNhdGU8L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0XHRcdDxpIGlkPVwidXBsb2FkU3Bpbm5lclwiIGNsYXNzPVwiZmFzIGZhLWNpcmNsZS1ub3RjaCBmYS1zcGluIHRleHQtcHJpbWFyeSBhbGlnbi1taWRkbGUgbWwtMVwiPjwvaT5cblx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZmxleC1ncm93LTEgdGV4dC1yaWdodFwiPlxuXHRcdFx0XHRcdFx0XHRcdFx0PGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJrLWJ1dHRvbiBrLXNlY29uZGFyeVwiIGRhdGEtZGlzbWlzcz1cIm1vZGFsXCI+Q2FuY2VsPC9idXR0b24+XG5cdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHQ8ZGl2IGlkPVwidXBsb2FkRXJyb3JNc2dcIiBjbGFzcz1cInRleHQtZGFuZ2VyIG10LTNcIj48L2Rpdj5cblx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdDwvZGl2PlxuXHRcdGA7XG5cblx0XHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRcdCQodGhpcykuYXBwZW5kKGBcblx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNSBjb2wtbGctNCBjb2wtZm9ybS1sYWJlbCBmb3JtLWxhYmVsLWNvbnRhaW5lclwiPlxuXHRcdFx0XHQ8bGFiZWwgY2xhc3M9XCJmb3JtLWxhYmVsXCI+VXBsb2FkIGNlcnRpZmljYXRlIDxpIGNsYXNzPVwiZmFzIGZhLXF1ZXN0aW9uLWNpcmNsZSB0ZXh0LW11dGVkIGhlbHBcIiB0aXRsZT1cIlVwbG9hZCBhbiBTU0wgY2VydGlmaWNhdGUncyBwcm90ZWN0ZWQga2V5c3RvcmUgdG8gdGhlIHNlcnZlclwiPjwvaT48L2xhYmVsPlxuXHRcdFx0PC9kaXY+XG5cdFx0XHQ8ZGl2IGNsYXNzPVwiaW5uZXItd2lkZ2V0IGFsaWduLXNlbGYtY2VudGVyIGFsaWduLXNlbGYtc20tc3RhcnQgY29sLWF1dG9cIj5cblx0XHRcdFx0PGJ1dHRvbiBpZD1cIm1hbmFnZVNzbEJ1dHRvblwiIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImstYnV0dG9uIGstcHJpbWFyeVwiIGRpc2FibGVkPjxpIGNsYXNzPVwiZmFzIGZhLWNvZyBtci0xXCI+PC9pPk1hbmFnZTwvYnV0dG9uPlxuXHRcdFx0PC9kaXY+XG5cdFx0YCk7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXJzIHRvIE1hbmFnZSBidXR0b24gY2xpY2tcblx0XHQkKCcjbWFuYWdlU3NsQnV0dG9uJywgJCh0aGlzKSkub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbk1hbmFnZVNzbENsaWNrLCB0aGlzKSk7XG5cdH1cblxuXHRkZXN0cm95KClcblx0e1xuXHRcdC8vIFJlbW92ZSBldmVudCBsaXN0ZW5lclxuXHRcdCQoJyNtYW5hZ2VTc2xCdXR0b24nLCAkKHRoaXMpKS5vZmYoJ2NsaWNrJyk7XG5cblx0XHQvLyBIaWRlIG1vZGFsICh3aGljaCBpbiB0dXJuIGRlc3Ryb3lzIGl0KVxuXHRcdGxldCBtb2RhbEVsZW1lbnQgPSAkKCcjdXBsb2FkTW9kYWwnLCAkKHRoaXMpKTtcblxuXHRcdGlmIChtb2RhbEVsZW1lbnQpXG5cdFx0XHRtb2RhbEVsZW1lbnQubW9kYWwoJ2hpZGUnKTtcblx0fVxuXG5cdGdldCBlbmFibGVkKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9pc0VuYWJsZWQ7XG5cdH1cblxuXHRzZXQgZW5hYmxlZCh2YWx1ZSlcblx0e1xuXHRcdHRoaXMuX2lzRW5hYmxlZCA9IHZhbHVlO1xuXG5cdFx0Ly8gRW5hYmxlL2Rpc2FibGUgTWFuYWdlIGJ1dHRvblxuXHRcdCQoJyNtYW5hZ2VTc2xCdXR0b24nLCAkKHRoaXMpKS5hdHRyKCdkaXNhYmxlZCcsICF2YWx1ZSk7XG5cblx0XHQvLyBFbmFibGUvZGlzYWJsZSBtb2RhbFxuXHRcdGxldCBtb2RhbEVsZW1lbnQgPSAkKCcjdXBsb2FkTW9kYWwnLCAkKHRoaXMpKTtcblxuXHRcdGlmIChtb2RhbEVsZW1lbnQpXG5cdFx0e1xuXHRcdFx0Ly8gRGlzYWJsZSBtb2RhbCBjbG9zZSBidXR0b25zXG5cdFx0XHQkKCdidXR0b25bZGF0YS1kaXNtaXNzPVwibW9kYWxcIl0nLCBtb2RhbEVsZW1lbnQpLmF0dHIoJ2Rpc2FibGVkJywgIXZhbHVlKTtcblxuXHRcdFx0Ly8gRGlzYWJsZSB1cGxvYWQgYnV0dG9uXG5cdFx0XHQkKCcjdXBsb2FkU3NsQnV0dG9uJywgbW9kYWxFbGVtZW50KS5hdHRyKCdkaXNhYmxlZCcsICF2YWx1ZSk7XG5cblx0XHRcdC8vIERpc2FibGUgZmllbGRzZXRcblx0XHRcdCQoJyN1cGxvYWRGaWVsZHNldCcsIG1vZGFsRWxlbWVudCkuYXR0cignZGlzYWJsZWQnLCAhdmFsdWUpO1xuXHRcdH1cblx0fVxuXG5cdGdldCB1cGxvYWRUYXJnZXRDb25maWcoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3VwbG9hZFRhcmdldENvbmZpZztcblx0fVxuXG5cdHNldCB1cGxvYWRUYXJnZXRDb25maWcoZGF0YSlcblx0e1xuXHRcdHRoaXMuX3VwbG9hZFRhcmdldENvbmZpZyA9IGRhdGE7XG5cdH1cblxuXHRfb25NYW5hZ2VTc2xDbGljaygpXG5cdHtcblx0XHQvLyBJbml0aWFsaXplIGFuZCBzaG93IG1vZGFsXG5cdFx0dGhpcy5fc2hvd01vZGFsKCk7XG5cdH1cblxuXHRfb25VcGxvYWRTc2xDbGljaygpXG5cdHtcblx0XHRpZiAodGhpcy5fdmFsaWRhdGUoKSlcblx0XHRcdHRoaXMuX3N0YXJ0U3NsQ2VydFVwbG9hZCgpO1xuXHR9XG5cblx0X3Nob3dNb2RhbCgpXG5cdHtcblx0XHQvLyBBcHBlbmQgbW9kYWwgaHRtbFxuXHRcdCQodGhpcykuYXBwZW5kKHRoaXMuX21vZGFsSHRtbCk7XG5cblx0XHRsZXQgbW9kYWxFbGVtZW50ID0gJCgnI3VwbG9hZE1vZGFsJywgJCh0aGlzKSk7XG5cblx0XHQvLyBIaWRlIFNTTCBjZXJ0aWZpY2F0ZSB1cGxvYWQgc3Bpbm5lciBhbmQgZXJyb3IgbWVzc2FnZSBjb250YWluZXJcblx0XHQkKCcjdXBsb2FkU3Bpbm5lcicsIG1vZGFsRWxlbWVudCkuaGlkZSgpO1xuXHRcdCQoJyN1cGxvYWRFcnJvck1zZycsIG1vZGFsRWxlbWVudCkuaGlkZSgpO1xuXHRcdCQoJyN1cGxvYWRFcnJvck1zZycsIG1vZGFsRWxlbWVudCkudGV4dCgnJyk7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXIgdG8gVXBsb2FkIGJ1dHRvbiBjbGlja1xuXHRcdCQoJyN1cGxvYWRTc2xCdXR0b24nLCBtb2RhbEVsZW1lbnQpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25VcGxvYWRTc2xDbGljaywgdGhpcykpO1xuXG5cdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIG1vZGFsIGhpZGUgZXZlbnRcblx0XHRtb2RhbEVsZW1lbnQub24oJ2hpZGRlbi5icy5tb2RhbCcsICQucHJveHkodGhpcy5fZGVzdHJveU1vZGFsLCB0aGlzKSk7XG5cblx0XHQvLyBJbml0aWFsaXplIGtlbmRvIHVwbG9hZGVyXG5cdFx0dGhpcy5fdXBsb2FkV2lkZ2V0ID0gbW9kYWxFbGVtZW50LmZpbmQoJyN1cGxvYWRlcicpLmtlbmRvVXBsb2FkKHtcblx0XHRcdGFsbG93ZWRFeHRlbnNpb25zOiBbJy5qa3MnXSxcblx0XHRcdG11bHRpcGxlOiBmYWxzZSxcblx0XHRcdHRlbXBsYXRlOiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdFx0XHRkYXRhSXRlbS5ieXRlc1RvU2l6ZSA9IGJ5dGVzVG9TaXplOyAvLyBQYXNzIGJ5dGVzVG9TaXplIHV0aWxpdHkgZnVuY3Rpb24gdG8gdGVtcGxhdGVcblx0XHRcdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdFx0XHQ8c3BhbiBjbGFzcz0nay1wcm9ncmVzcyB3LTEwMCc+PC9zcGFuPlxuXHRcdFx0XHRcdDxzcGFuIGNsYXNzPVwiXCI+XG5cdFx0XHRcdFx0XHQ8c3BhbiBjbGFzcz1cImstZmlsZS1uYW1lXCIgdGl0bGU9XCIjPW5hbWUjXCI+Iz1uYW1lIzwvc3Bhbj5cblx0XHRcdFx0XHRcdDxzcGFuIGNsYXNzPVwiay1maWxlLXNpemVcIj5TaXplOiAjPWJ5dGVzVG9TaXplKHNpemUsIDEsICdCeXRlcycpIzwvc3Bhbj5cblx0XHRcdFx0XHQ8L3NwYW4+XG5cdFx0XHRcdGApKGRhdGFJdGVtKTtcblx0XHRcdH0sXG5cdCAgICAgICAgbG9jYWxpemF0aW9uOiB7XG5cdCAgICAgICAgICAgIHNlbGVjdDogJ1NlbGVjdCBmaWxlLi4uJ1xuXHQgICAgICAgIH1cbiAgICAgICAgfSkuZGF0YSgna2VuZG9VcGxvYWQnKTtcblxuXHRcdC8vIEluaXRpYWxpemUga2VuZG8gdmFsaWRhdGlvbiBvbiB1cGxvYWRlciBzdWJmb3JtXG5cdFx0Ly8gTk9URTogd2UgdXNlIHNlcGFyYXRlIHZhbGlkYXRvcnMgdG8gYmUgYWJsZSB0byBkaXNhYmxlICd2YWxpZGF0ZU9uQmx1cicgb24gdGhlIHVwbG9hZGVyLFxuXHRcdC8vIGJlY2F1c2UgaXQgY2F1c2VzIHRoZSBlcnJvciBtZXNzYWdlIHRvIGFwcGVhciBhcyBzb29uIGFzIHRoZSBcIlNlbGVjdCBmaWxlXCIgYnV0dG9uIGlzIGNsaWNrZWRcblx0XHR0aGlzLl92YWxpZGF0b3IxID0gbW9kYWxFbGVtZW50LmZpbmQoJyN1cGxvYWRlclN1YmZvcm0nKS5rZW5kb1ZhbGlkYXRvcih7XG5cdFx0XHR2YWxpZGF0ZU9uQmx1cjogZmFsc2UsXG5cdFx0XHRydWxlczoge1xuXHRcdFx0XHR1cGxvYWQ6IGZ1bmN0aW9uKGlucHV0KSB7XG5cdFx0XHRcdFx0bGV0IHZhbGlkID0gZmFsc2U7XG5cdFx0XHRcdFx0aWYgKGlucHV0LmlzKCdbdHlwZT1maWxlXScpKVxuXHRcdFx0XHRcdFx0dmFsaWQgPSBpbnB1dC5jbG9zZXN0KCcuay11cGxvYWQnKS5maW5kKCcuay1maWxlJykubGVuZ3RoID4gMDtcblxuXHRcdFx0XHRcdHJldHVybiB2YWxpZDtcblx0ICAgICAgICAgICAgfVxuXHRcdFx0fVxuXHRcdH0pLmRhdGEoJ2tlbmRvVmFsaWRhdG9yJyk7XG5cblx0XHQvLyBJbml0aWFsaXplIGtlbmRvIHZhbGlkYXRpb24gb24gcGFzc3dvcmRzIHN1YmZvcm1cblx0XHR0aGlzLl92YWxpZGF0b3IyID0gbW9kYWxFbGVtZW50LmZpbmQoJyNwYXNzd29yZHNTdWJmb3JtJykua2VuZG9WYWxpZGF0b3Ioe1xuXHRcdFx0dmFsaWRhdGVPbkJsdXI6IHRydWUsXG5cdFx0XHRydWxlczoge1xuXHRcdFx0XHR2ZXJpZnlLc1Bhc3N3b3JkOiAkLnByb3h5KGZ1bmN0aW9uKGlucHV0KSB7XG5cdFx0XHRcdFx0bGV0IHZhbGlkID0gdHJ1ZTtcblx0XHRcdFx0XHRpZiAoaW5wdXQuaXMoJ1tuYW1lPWNvbmZpcm1Lc1Bhc3N3b3JkXScpKVxuXHRcdFx0XHRcdFx0dmFsaWQgPSBpbnB1dC52YWwoKSA9PT0gJCh0aGlzKS5maW5kKCcja3NQYXNzd29yZCcpLnZhbCgpO1xuXHRcdFx0XHRcdHJldHVybiB2YWxpZDtcblx0XHRcdFx0fSwgdGhpcyksXG5cdFx0XHRcdHZlcmlmeUFkbVBhc3N3b3JkOiAkLnByb3h5KGZ1bmN0aW9uKGlucHV0KSB7XG5cdFx0XHRcdFx0bGV0IHZhbGlkID0gdHJ1ZTtcblx0XHRcdFx0XHRpZiAoaW5wdXQuaXMoJ1tuYW1lPWNvbmZpcm1BZG1pblBhc3N3b3JkXScpKVxuXHRcdFx0XHRcdFx0dmFsaWQgPSBpbnB1dC52YWwoKSA9PT0gJCh0aGlzKS5maW5kKCcjYWRtaW5QYXNzd29yZCcpLnZhbCgpO1xuXHRcdFx0XHRcdHJldHVybiB2YWxpZDtcblx0XHRcdFx0fSwgdGhpcylcblx0XHRcdH0sXG5cdFx0XHRtZXNzYWdlczoge1xuXHRcdFx0XHR2ZXJpZnlLc1Bhc3N3b3JkOiAnUGFzc3dvcmQgbm90IG1hdGNoaW5nJyxcblx0XHRcdFx0dmVyaWZ5QWRtUGFzc3dvcmQ6ICdQYXNzd29yZCBub3QgbWF0Y2hpbmcnLFxuXHRcdFx0fVxuXHRcdH0pLmRhdGEoJ2tlbmRvVmFsaWRhdG9yJyk7XG5cblx0XHQvLyBJbml0aWFsaXplIGJvb3RzdHJhcCBtb2RhbFxuXHRcdG1vZGFsRWxlbWVudC5tb2RhbCh7XG5cdFx0XHRiYWNrZHJvcDogJ3N0YXRpYycsXG5cdFx0XHRrZXlib2FyZDogZmFsc2UsXG5cdFx0fSk7XG5cdH1cblxuXHRfZGVzdHJveU1vZGFsKClcblx0e1xuXHRcdGxldCBtb2RhbEVsZW1lbnQgPSAkKCcjdXBsb2FkTW9kYWwnLCAkKHRoaXMpKTtcblxuXHRcdGlmIChtb2RhbEVsZW1lbnQpXG5cdFx0e1xuXHRcdFx0Ly8gUmVtb3ZlIGxpc3RlbmVyc1xuXHRcdFx0JCgnI3VwbG9hZFNzbEJ1dHRvbicsIG1vZGFsRWxlbWVudCkub2ZmKCdjbGljaycpO1xuXHRcdFx0bW9kYWxFbGVtZW50Lm9mZignaGlkZGVuLmJzLm1vZGFsJyk7XG5cblx0XHRcdC8vIERlc3Ryb3kgZXZlcnl0aGluZyBLZW5kb1xuXHRcdFx0a2VuZG8uZGVzdHJveShtb2RhbEVsZW1lbnQpO1xuXG5cdFx0XHQvLyBEaXNwb3NlIG1vZGFsXG5cdFx0XHRtb2RhbEVsZW1lbnQubW9kYWwoJ2Rpc3Bvc2UnKTtcblxuXHRcdFx0Ly8gUmVtb3ZlIGh0bWxcblx0XHRcdG1vZGFsRWxlbWVudC5yZW1vdmUoKTtcblx0XHRcdG1vZGFsRWxlbWVudCA9IG51bGw7XG5cdFx0fVxuXHR9XG5cblx0X3ZhbGlkYXRlKClcblx0e1xuXHRcdGxldCB2YWwxID0gdGhpcy5fdmFsaWRhdG9yMS52YWxpZGF0ZSgpO1xuXHRcdGxldCB2YWwyID0gdGhpcy5fdmFsaWRhdG9yMi52YWxpZGF0ZSgpO1xuXG5cdFx0cmV0dXJuIHZhbDEgJiYgdmFsMjtcblx0fVxuXG5cdF9zdGFydFNzbENlcnRVcGxvYWQoKVxuXHR7XG5cdFx0aWYgKCF0aGlzLl91cGxvYWRUYXJnZXRDb25maWcpXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ1VwbG9hZCB0YXJnZXQgY29uZmlndXJhdGlvbiBub3Qgc2V0Jyk7XG5cblx0XHRsZXQgbW9kYWxFbGVtZW50ID0gJCgnI3VwbG9hZE1vZGFsJywgJCh0aGlzKSk7XG5cblx0XHRpZiAobW9kYWxFbGVtZW50KVxuXHRcdHtcblx0XHRcdGxldCBjZXJ0RGF0YSA9IHt9O1xuXHRcdFx0Y2VydERhdGEuZmlsZSA9IHRoaXMuX3VwbG9hZFdpZGdldC5nZXRGaWxlcygpWzBdO1xuXHRcdFx0Y2VydERhdGEua3NQYXNzd29yZCA9ICQoJyNrc1Bhc3N3b3JkJywgbW9kYWxFbGVtZW50KS52YWwoKTtcblx0XHRcdGNlcnREYXRhLmFkbWluUGFzc3dvcmQgPSAkKCcjYWRtaW5QYXNzd29yZCcsIG1vZGFsRWxlbWVudCkudmFsKCk7XG5cblx0XHRcdC8vIERpc2FibGUgbW9kYWxcblx0XHRcdHRoaXMuZW5hYmxlZCA9IGZhbHNlO1xuXG5cdFx0XHQvLyBIaWRlIHByZXZpb3VzIGVycm9yIGFuZCBzaG93IHNwaW5uZXJcblx0XHRcdCQoJyN1cGxvYWRTcGlubmVyJywgbW9kYWxFbGVtZW50KS5zaG93KCk7XG5cdFx0XHQkKCcjdXBsb2FkRXJyb3JNc2cnLCBtb2RhbEVsZW1lbnQpLmhpZGUoKTtcblx0XHRcdCQoJyN1cGxvYWRFcnJvck1zZycsIG1vZGFsRWxlbWVudCkudGV4dCgnJyk7XG5cblx0XHRcdC8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuXHRcdFx0Ly8gR2VuZXJhdGUgSW5pdCBWZWN0b3Jcblx0XHRcdGxldCBybmdWYWx1ZXMgPSBbXTtcblx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgMTY7IGkrKylcblx0XHRcdFx0cm5nVmFsdWVzLnB1c2goTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMjU2KSk7XG5cblx0XHRcdGxldCBpdiA9IG5ldyBVaW50OEFycmF5KHJuZ1ZhbHVlcyk7XG5cblx0XHRcdC8vIEdlbmVyYXRlIHNlY3JldCBrZXkgYnkgTUQ1LWVuY29kaW5nIGFkbWluIHBhc3N3b3JkICsgc2Vzc2lvbiB0b2tlblxuXHRcdFx0bGV0IG1kNVBhc3MgPSB0aGlzLl9iaW5hcnlNRDUoY2VydERhdGEuYWRtaW5QYXNzd29yZCArIHRoaXMuX3VwbG9hZFRhcmdldENvbmZpZy5zZXNzaW9uVG9rZW4pO1xuXG5cdFx0XHQvLyBFbmNyeXB0IGtleXN0b3JlIHBhc3N3b3JkIHZpYSBBRVMgKDEyOGJpdClcblx0XHRcdGxldCBlbmNyeXB0ZWRQd2QgPSB0aGlzLl9hZXNFbmNyeXB0KGNlcnREYXRhLmtzUGFzc3dvcmQsIG1kNVBhc3MsIGl2KTtcblxuXHRcdFx0Ly8gRW5jb2RlIElWIHVzaW5nIEJhc2U2NFxuXHRcdFx0bGV0IGVuY29kZWRJdiA9IHRoaXMuX2I2NEVuY29kZShpdik7XG5cblx0XHRcdC8vIEVuY29kZSBlbmNyeXB0ZWQgcGFzc3dvcmQgdXNpbmcgQmFzZTY0XG5cdFx0XHRsZXQgZW5jb2RlZFB3ZCA9IHRoaXMuX2I2NEVuY29kZShlbmNyeXB0ZWRQd2QpO1xuXG5cdFx0XHQvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cblx0XHRcdC8vIFNldCBwYXJhbWV0ZXJzIHRvIGJlIHNlbnQgd2l0aCB0aGUgY2VydGlmaWNhdGUga2V5c3RvcmUgZmlsZVxuXHRcdFx0Y29uc3QgcGFyYW1zID0gbmV3IEZvcm1EYXRhKCk7XG5cdFx0XHRwYXJhbXMuYXBwZW5kKCdmaWxlc1tdJywgY2VydERhdGEuZmlsZS5yYXdGaWxlKTtcblx0XHRcdHBhcmFtcy5hcHBlbmQoJ19faXYnLCBlbmNvZGVkSXYpO1xuXHRcdFx0cGFyYW1zLmFwcGVuZCgnX19wYXNzd29yZCcsIGVuY29kZWRQd2QpO1xuXHRcdFx0cGFyYW1zLmFwcGVuZCgnX19tb2R1bGUnLCB0aGlzLl91cGxvYWRUYXJnZXRDb25maWcubW9kdWxlSWQpO1xuXG5cdFx0XHQvLyBTZXQgZGVzdGluYXRpb24gdXJsXG5cdFx0XHRjb25zdCB1cmwgPSB0aGlzLl91cGxvYWRUYXJnZXRDb25maWcucHJvdG9jb2wgKyAnOi8vJyArIHRoaXMuX3VwbG9hZFRhcmdldENvbmZpZy5ob3N0ICsgJzonICsgdGhpcy5fdXBsb2FkVGFyZ2V0Q29uZmlnLnBvcnQgKyAnL0JsdWVCb3gvU0ZTMlhGaWxlVXBsb2FkP3Nlc3NIYXNoSWQ9JyArIHRoaXMuX3VwbG9hZFRhcmdldENvbmZpZy5zZXNzaW9uVG9rZW47XG5cblx0XHRcdC8vIFN0YXJ0IHVwbG9hZFxuXHRcdFx0ZmV0Y2godXJsLCB7XG5cdFx0XHRcdG1ldGhvZDogJ1BPU1QnLFxuXHRcdFx0XHRib2R5OiBwYXJhbXMsXG5cdFx0XHRcdG1vZGU6ICduby1jb3JzJ1xuXHRcdFx0fSkudGhlbigkLnByb3h5KHRoaXMuX29uU3NsQ2VydFVwbG9hZEVuZCwgdGhpcykpO1xuXHRcdH1cblx0fVxuXG5cdF9vblNzbENlcnRVcGxvYWRFbmQocmVzcG9uc2UpXG5cdHtcblx0XHQvLyBOb3RoaW5nIHRvIGRvOiB3ZSBoYXZlIHRvIHdhaXQgdGhlIHVwbG9hZCBwcm9jZXNzIGNvbXBsZXRpb24gdG8gYmUgc2lnbmFsZWQgYnkgdGhlIHNlcnZlciB0aHJvdWdoIHRoZSBkZWRpY2F0ZWQgRXh0ZW5zaW9uIHJlc3BvbnNlXG5cblx0XHQvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cblx0XHQvLyBUT0RPIFNob3VsZCB3ZSBoYW5kbGUgdGhpcyByZXNwb25zZSBpbiBzb21lIHdheT8gRm9yIHNvbWUgdW5rbm93biByZWFzb24gd2UgYWx3YXlzIGdldCBvaz1mYWxzZSBhbmQgc3RhdHVzPTBcblx0XHQvL2NvbnNvbGUubG9nKHJlc3BvbnNlKVxuXHRcdC8vY29uc29sZS5sb2cocmVzcG9uc2Uub2spXG5cdFx0Ly9jb25zb2xlLmxvZyhyZXNwb25zZS5zdGF0dXMpXG5cdH1cblxuXHQvKipcblx0ICogTWV0aG9kIGNhbGxlZCBieSBwYXJlbnQgd2hlbiB1cGxvYWQgZmFpbGVkLlxuXHQgKi9cblx0b25Tc2xDZXJ0VXBsb2FkRXJyb3IoZXJyb3IpXG5cdHtcblx0XHRsZXQgbW9kYWxFbGVtZW50ID0gJCgnI3VwbG9hZE1vZGFsJywgJCh0aGlzKSk7XG5cblx0XHRpZiAobW9kYWxFbGVtZW50KVxuXHRcdHtcblx0XHRcdC8vIEVuYWJsZSBtb2RhbFxuXHRcdFx0dGhpcy5lbmFibGVkID0gdHJ1ZTtcblxuXHRcdFx0Ly8gU2hvdyB1cGxvYWQgZXJyb3Jcblx0XHRcdCQoJyN1cGxvYWRFcnJvck1zZycsIG1vZGFsRWxlbWVudCkuc2hvdygpO1xuXHRcdFx0JCgnI3VwbG9hZEVycm9yTXNnJywgbW9kYWxFbGVtZW50KS50ZXh0KGVycm9yICsgJy4nKTtcblxuXHRcdFx0Ly8gSGlkZSBzcGlubmVyXG5cdFx0XHQkKCcjdXBsb2FkU3Bpbm5lcicsIG1vZGFsRWxlbWVudCkuaGlkZSgpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBNZXRob2QgY2FsbGVkIGJ5IHBhcmVudCB3aGVuIHVwbG9hZCBpcyBjb21wbGV0ZWQgc3VjY2Vzc2Z1bGx5LlxuXHQgKi9cblx0b25Tc2xDZXJ0VXBsb2FkU3VjY2VzcygpXG5cdHtcblx0XHRsZXQgbW9kYWxFbGVtZW50ID0gJCgnI3VwbG9hZE1vZGFsJywgJCh0aGlzKSk7XG5cblx0XHRpZiAobW9kYWxFbGVtZW50KVxuXHRcdHtcblx0XHRcdC8vIEVuYWJsZSBtb2RhbFxuXHRcdFx0dGhpcy5lbmFibGVkID0gdHJ1ZTtcblxuXHRcdFx0Ly8gSGlkZSBzcGlubmVyXG5cdFx0XHQkKCcjdXBsb2FkU3Bpbm5lcicsIG1vZGFsRWxlbWVudCkuaGlkZSgpO1xuXG5cdFx0XHQvLyBIaWRlIG1vZGFsXG5cdFx0XHRtb2RhbEVsZW1lbnQubW9kYWwoJ2hpZGUnKTtcblx0XHR9XG5cdH1cblxuXHQvLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5cdC8qXG5cdCAqIFRha2VzIGEgc3RyaW5nIGFuZCByZXR1cm5zIHRoZSBNRDUgYXMgVWludDhBcnJheVxuXHQgKi9cblx0X2JpbmFyeU1ENShzdHIpXG5cdHtcblx0XHRsZXQgTUQ1ID0gbmV3IFNGUzJYLk1ENSgpO1xuXHRcdGxldCBoZXhTdHIgPSBNRDUuaGV4X21kNShzdHIpO1xuXG5cdFx0cmV0dXJuIHRoaXMuX2hleEJ5dGVTdHJpbmdUb0J5dGVBcnJheShoZXhTdHIpO1xuXHR9XG5cblx0Lypcblx0ICogSGV4IGJ5dGVzIC0tLT4gQWN0dWFsIGJ5dGVbXSBhcyBVaW50OEFycmF5XG5cdCAqL1xuXHRfaGV4Qnl0ZVN0cmluZ1RvQnl0ZUFycmF5KGhleEJ5dGVTdHJpbmcpXG5cdHtcblx0ICAgIGxldCBieXRlcyA9IG5ldyBVaW50OEFycmF5KDE2KTsgLy8gTUQ1IGZpeGVkIG91dHB1dCBzaXplXG5cblx0ICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaGV4Qnl0ZVN0cmluZy5sZW5ndGg7KVxuXHQgICAge1xuXHQgICAgICAgIGxldCBoZXhCeXRlID0gaGV4Qnl0ZVN0cmluZ1tpKytdICsgaGV4Qnl0ZVN0cmluZ1tpKytdO1xuXHQgICAgICAgIGxldCBieXRlID0gcGFyc2VJbnQoaGV4Qnl0ZSwgMTYpO1xuXG5cdCAgICAgICAgYnl0ZXNbaSAvIDIgLSAxXSA9IGJ5dGU7XG5cdCAgICB9XG5cblx0ICAgIHJldHVybiBieXRlcztcblx0fVxuXG5cdC8qXG5cdCAqIEVuY3J5cHQgdXNpbmcgQUVTLCBtb2RlIENCQywgUEtDUyM3IHBhZGRpbmdcblx0ICpcblx0ICogdGV4dCBcdFx0LT4gdGhlIHRleHQgd2Ugd2FudCB0byBlbmNvZGVcblx0ICoga2V5IFx0XHQtPiB0aGUgQUVTIGtleVxuXHQgKiBpdiAgXHRcdC0+IHRoZSBBRVMvQ0JDIGluaXQgdmVjdG9yXG5cdCAqXG5cdCAqIFJldHVybnMgXHQtPiBVaW50OEFycmF5XG5cdCAqL1xuXHRfYWVzRW5jcnlwdCh0ZXh0LCBrZXksIGl2KVxuXHR7XG5cdFx0bGV0IHRleHRCeXRlcyA9IGFlc2pzLnV0aWxzLnV0ZjgudG9CeXRlcyh0ZXh0KTsgXHRcdC8vIEdldCBVVEYtOCBieXRlc1xuXHRcdGxldCBhZXNDQkMgPSBuZXcgYWVzanMuTW9kZU9mT3BlcmF0aW9uLmNiYyhrZXksIGl2KTtcdC8vIEluaXQgQ0JDIG1vZGVcblx0XHR0ZXh0Qnl0ZXMgPSBhZXNqcy5wYWRkaW5nLnBrY3M3LnBhZCh0ZXh0Qnl0ZXMpOyBcdFx0Ly8gUEtDUyM3IHBhZGRpbmdcblxuXHRcdC8vIEVuY3J5cHRcblx0XHRyZXR1cm4gYWVzQ0JDLmVuY3J5cHQodGV4dEJ5dGVzKTtcblx0fVxuXG5cdC8qXG5cdCAqIEVuY29kZSBwYXNzZWQgYnl0ZSBhcnJheSAtLT4gQmFzZTY0IHJlcHJlc2VudGF0aW9uXG5cdCAqIFJldHVybnMgLS0+IHN0cmluZ1xuXHQgKi9cblx0X2I2NEVuY29kZShiYXJyYXkpXG5cdHtcblx0XHRyZXR1cm4gYnRvYShTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIGJhcnJheSkpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnc3NsLWNlcnRpZmljYXRlLW1hbmFnZXInKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnc3NsLWNlcnRpZmljYXRlLW1hbmFnZXInLCBTc2xDZXJ0aWZpY2F0ZU1hbmFnZXIpO1xuIiwiaW1wb3J0IHtCYXNlTW9kdWxlfSBmcm9tICcuL2Jhc2UtbW9kdWxlJztcbmltcG9ydCB7Q29uZmlnSW50ZXJmYWNlQnVpbGRlcn0gZnJvbSAnLi4vdXRpbHMvdWlidWlsZGVyL2NvbmZpZy1pbnRlcmZhY2UtYnVpbGRlcic7XG5pbXBvcnQge1NzbENlcnRpZmljYXRlTWFuYWdlcn0gZnJvbSAnLi4vY29tcG9uZW50cy9tb2R1bGUtc3BlY2lmaWMvc3NsLWNlcnRpZmljYXRlLW1hbmFnZXInO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTZXJ2ZXJDb25maWd1cmF0b3IgZXh0ZW5kcyBCYXNlTW9kdWxlXG57XG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHQgICAgc3VwZXIoJ3NlcnZlckNvbmZpZycpO1xuXG5cdFx0Ly8gT3V0Z29pbmcgcmVxdWVzdHNcblx0XHR0aGlzLlJFUV9JTklUID0gJ2luaXQnO1xuXHRcdHRoaXMuUkVRX0dFVF9DT05GSUcgPSAnZ2V0Q29uZmlnJztcblx0XHR0aGlzLlJFUV9VUERBVEVfQ09ORklHID0gJ3VwZENvbmZpZyc7XG5cdFx0dGhpcy5SRVFfVVBEQVRFX0dFT19EQiA9ICd1cGRHZW9EYic7XG5cblx0XHQvLyBJbmNvbWluZyByZXNwb25zZXNcblx0XHR0aGlzLlJFU1BfSU5JVCA9ICdpbml0Jztcblx0XHR0aGlzLlJFU1BfQ09ORklHID0gJ2NvbmZpZyc7XG5cdFx0dGhpcy5SRVNQX0NPTkZJR19VUERBVEVfQ09ORklSTSA9ICdjb25maWdVcGRhdGUnO1xuXHRcdHRoaXMuUkVTUF9DT05GSUdfQ0hBTkdFRF9BTEVSVCA9ICdjb25maWdBbGVydCc7XG5cdFx0dGhpcy5SRVNQX1NTTF9VUExPQURfRVJST1IgPSAnc3NsVXBsb2FkRXJyb3InO1xuXHRcdHRoaXMuUkVTUF9TU0xfVVBMT0FEX0NPTkZJUk0gPSAnc3NsVXBsb2FkJztcblx0XHR0aGlzLlJFU1BfVVBEQVRFX0dFT19EQiA9ICdnZW9EYlVwZGF0ZSc7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBDT01NT04gTU9EVUxFIElOVEVSRkFDRSBNRVRIT0RTXG5cdC8vIFRoaXMgbWVtYmVycyBhcmUgdXNlZCBieSB0aGUgbWFpbiBjb250cm9sbGVyXG5cdC8vIHRvIGNvbW11bmljYXRlIHdpdGggdGhlIG1vZHVsZSdzIGNvbnRyb2xsZXIuXG5cdC8vIFRoaXMgbWV0aG9kcyBvdmVycmlkZSB0aG9zZSBpbiBCYXNlTW9kdWxlIGNsYXNzLlxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdGluaXRpYWxpemUoaWREYXRhLCBzaGVsbENvbnRyb2xsZXIpXG5cdHtcblx0XHQvLyBDYWxsIHN1cGVyIG1ldGhvZFxuXHRcdHN1cGVyLmluaXRpYWxpemUoaWREYXRhLCBzaGVsbENvbnRyb2xsZXIpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBwcm9ncmVzcyBiYXJcblx0XHQkKCcjc3JjLXByb2dyZXNzQmFyJykua2VuZG9Qcm9ncmVzc0Jhcih7XG5cdFx0XHRtaW46IDAsXG4gICAgICAgICAgICBtYXg6IDEwMCxcblx0XHRcdHZhbHVlOiBmYWxzZSxcbiAgICAgICAgICAgIHR5cGU6ICd2YWx1ZScsXG4gICAgICAgICAgICBhbmltYXRpb246IHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNDAwXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG5cdFx0Ly8gQ3JlYXRlIGludGVyZmFjZSBidWlsZGVyIGluc3RhbmNlXG5cdFx0dGhpcy5faW50ZXJmYWNlQnVpbGRlciA9IG5ldyBDb25maWdJbnRlcmZhY2VCdWlsZGVyKCk7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXIgdG8gR2VvTGl0ZTIgZGF0YWJhc2UgdXBkYXRlIGJ1dHRvblxuXHRcdCQoJyNzcmMtdXBkYXRlR2VvbG9jRGJCdXR0b24nKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uVXBkYXRlR2VvbG9jRGJDbGljaywgdGhpcykpO1xuXG5cdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIGludGVyZmFjZSBidXR0b25zXG5cdFx0JCgnI3NyYy1yZWxvYWRCdXR0b24nKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uUmVsb2FkQ2xpY2ssIHRoaXMpKTtcblx0XHQkKCcjc3JjLXN1Ym1pdEJ1dHRvbicpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25TdWJtaXRDbGljaywgdGhpcykpO1xuXG5cdFx0Ly8gU2F2ZSByZWYgdG8gU1NMIE1hbmFnZXJcblx0XHR0aGlzLl9zc2xDZXJ0TWFuYWdlciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzcmMtc3NsQ2VydE1hbmFnZXInKTtcblxuXHRcdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG5cdFx0Ly8gU2VuZCBpbml0aWFsaXphdGlvbiByZXF1ZXN0XG5cdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9JTklUKTtcblx0fVxuXG5cdGRlc3Ryb3koKVxuXHR7XG5cdFx0Ly8gQ2FsbCBzdXBlciBtZXRob2Rcblx0XHRzdXBlci5kZXN0cm95KCk7XG5cblx0XHQvLyBEZXN0cm95IFNTTCBDZXJ0aWZpY2F0ZSBNYW5hZ2VyXG5cdFx0dGhpcy5fc3NsQ2VydE1hbmFnZXIuZGVzdHJveSgpO1xuXG5cdFx0Ly8gUmVtb3ZlIGludGVyZmFjZSBidXR0b25zIGNsaWNrIGxpc3RlbmVyc1xuXHRcdCQoJyNzcmMtdXBkYXRlR2VvbG9jRGJCdXR0b24nKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3NyYy1yZWxvYWRCdXR0b24nKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3NyYy1zdWJtaXRCdXR0b24nKS5vZmYoJ2NsaWNrJyk7XG5cblx0XHQvLyBDbGVhciB0YWJzIGNvbnRhaW5lclxuXHRcdHRoaXMuX2NsZWFyVGFicygpO1xuXHR9XG5cblx0b25FeHRlbnNpb25Db21tYW5kKGNvbW1hbmQsIGRhdGEpXG5cdHtcblx0XHQvLyBJbml0aWFsaXphdGlvbiBkYXRhIHJlY2VpdmVkXG5cdFx0aWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX0lOSVQpXG5cdFx0e1xuXHRcdFx0Ly8gUmV0cmlldmUgbW9kdWxlIGlkIHNlbnQgYnkgdGhlIHNlcnZlciAocmVxdWlyZWQgYmVjYXVzZSBtdWx0aXBsZSBtb2R1bGVzIHVzZSBmaWxlIHVwbG9hZGluZyBzZXJ2aWNlKVxuXHRcdFx0Y29uc3QgdXBsb2FkTW9kdWxlSWQgPSBkYXRhLmdldFV0ZlN0cmluZygnbW9kSWQnKTtcblxuXHRcdFx0Ly8gU2V0IFNTTCB1cGxvYWQgbWFuYWdlciB0YXJnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0dGhpcy5fc3NsQ2VydE1hbmFnZXIudXBsb2FkVGFyZ2V0Q29uZmlnID0ge1xuXHRcdFx0XHRzZXNzaW9uVG9rZW46IHRoaXMuc21hcnRGb3guc2Vzc2lvblRva2VuLFxuXHRcdFx0XHRob3N0OiB0aGlzLnNtYXJ0Rm94LmNvbmZpZy5ob3N0LFxuXHRcdFx0XHRwb3J0OiB0aGlzLnNtYXJ0Rm94LmNvbmZpZy5wb3J0LFxuXHRcdFx0XHRtb2R1bGVJZDogdXBsb2FkTW9kdWxlSWQsXG5cdFx0XHRcdHByb3RvY29sOiB0aGlzLnNtYXJ0Rm94LmNvbmZpZy51c2VTU0wgPyAnaHR0cHMnIDogJ2h0dHAnXG5cdFx0XHR9O1xuXG5cdFx0XHQvLyBTZXJ2ZXIgc2VuZHMgYSBmbGFnIGluZGljYXRpbmcgaWYgZmlsZSB1cGxvYWRzIGFyZSBsb2NrZWRcblx0XHRcdC8vIFdlIHVzZSBpdCB0byBlbmFibGUgdGhlIFwiTWFuYWdlIFNTTCBjZXJ0aWZpY2F0ZVwiIGJ1dHRvblxuXHRcdFx0dGhpcy5fc3NsTG9ja2VkID0gZGF0YS5nZXRCb29sKCdsb2NrJyk7XG5cblx0XHRcdGlmICghdGhpcy5fc3NsTG9ja2VkKVxuXHRcdFx0XHQkKCcjc3JjLW1hbmFnZVNzbFdhcm4nKS5oaWRlKCk7XG5cblx0XHRcdC8vIFJlcXVlc3QgY29uZmlndXJhdGlvbiBkYXRhIHRvIHNlcnZlciBpbnN0YW5jZVxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9HRVRfQ09ORklHKTtcblx0XHR9XG5cblx0XHQvLyBTZXJ2ZXIgY29uZmlndXJhdGlvbiBkYXRhIHJlY2VpdmVkXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfQ09ORklHKVxuXHRcdHtcblx0XHRcdC8vIEJ1aWxkIHVzZXIgaW50ZXJmYWNlIGJhc2VkIG9uIHJlY2VpdmVkIGRhdGFcblx0XHRcdHRoaXMuX2ludGVyZmFjZUJ1aWxkZXIuYnVpbGRJbnRlcmZhY2UoZGF0YS5nZXRTRlNBcnJheSgnc2V0dGluZ3MnKSwgJ3NyYy10YWJOYXZpZ2F0b3InLCBmYWxzZSk7XG5cblx0XHRcdC8vIEVuYWJsZSBidXR0b25zXG5cdFx0XHR0aGlzLl9lbmFibGVCdXR0b25zKHRydWUpO1xuXG5cdFx0XHQvLyBJbml0aWFsaXplIFRhYk5hdmlnYXRvci1yYWxhdGVkIHdpZGdldHNcblx0XHRcdGlmICghdGhpcy5fdGFiTmF2SW5pdGlhbGl6ZWQpXG5cdFx0XHR7XG5cdFx0XHRcdC8vIEVuYWJsZSBzY3JvbGxpbmcgdGFic1xuXHRcdFx0XHQkKCcjc3JjLXRhYk5hdmlnYXRvciA+ICN0YWJzJykuc2Nyb2xsaW5nVGFicyh7XG5cdFx0XHRcdFx0Ym9vdHN0cmFwVmVyc2lvbjogNCxcblx0XHRcdFx0XHRzY3JvbGxUb1RhYkVkZ2U6IHRydWUsXG5cdFx0XHRcdFx0ZW5hYmxlU3dpcGluZzogdHJ1ZSxcblx0XHRcdFx0XHRkaXNhYmxlU2Nyb2xsQXJyb3dzT25GdWxseVNjcm9sbGVkOiB0cnVlLFxuXHRcdFx0XHRcdGNzc0NsYXNzTGVmdEFycm93OiAnZmEgZmEtY2hldnJvbi1sZWZ0Jyxcblx0XHRcdFx0XHRjc3NDbGFzc1JpZ2h0QXJyb3c6ICdmYSBmYS1jaGV2cm9uLXJpZ2h0J1xuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHR0aGlzLl90YWJOYXZJbml0aWFsaXplZCA9IHRydWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFJ1biB2YWxpZGF0aW9uICh0byByZW1vdmUgdmFsaWRhdGlvbiBtZXNzYWdlcyBpZiBkYXRhIHdhcyByZWxvYWRlZClcblx0XHRcdHRoaXMuX2ludGVyZmFjZUJ1aWxkZXIuY2hlY2tJc1ZhbGlkKCk7XG5cblx0XHRcdHRoaXMuX3N3aXRjaFZpZXcoJ3NyYy1tYWluJyk7XG5cdFx0fVxuXG5cdFx0Ly8gU2VydmVyIGNvbmZpZ3VyYXRpb24gdXBkYXRlIGNvbmZpcm1hdGlvblxuXHRcdGVsc2UgaWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX0NPTkZJR19VUERBVEVfQ09ORklSTSlcblx0XHR7XG5cdFx0XHQvLyBFbmFibGUgYnV0dG9uc1xuXHRcdFx0dGhpcy5fZW5hYmxlQnV0dG9ucyh0cnVlKTtcblxuXHRcdFx0Ly8gRW5hYmxlIGZvcm0gaXRlbXNcblx0XHRcdHRoaXMuX2ludGVyZmFjZUJ1aWxkZXIuZGlzYWJsZUludGVyZmFjZShmYWxzZSk7XG5cblx0XHRcdC8vIElmIHRoZSBjdXJyZW50IHVzZXIgaXMgdGhlIHVwZGF0ZXIsIHNob3cgYSBub3RpZmljYXRpb25cblx0XHRcdC8vIE90aGVyd2lzZSwgc2hvdyBhIGRpYWxvZyBib3ggc3VnZ2VzdGluZyB0byByZWxvYWRcblx0XHRcdGxldCB1cGRhdGVyID0gZGF0YS5nZXRVdGZTdHJpbmcoJ3VzZXInKTtcblxuXHRcdFx0aWYgKHVwZGF0ZXIgPT0gdGhpcy5zbWFydEZveC5teVNlbGYubmFtZSlcblx0XHRcdHtcblx0XHRcdFx0Ly8gUmVzZXQgdGhlICdtb2RpZmllZCcgZmxhZ1xuXHRcdFx0XHR0aGlzLl9pbnRlcmZhY2VCdWlsZGVyLnJlc2V0SXNNb2RpZmllZCgpO1xuXG5cdFx0XHRcdC8vIERpc3BsYXkgbm90aWZpY2F0aW9uXG5cdFx0XHRcdHRoaXMuc2hlbGxDdHJsLnNob3dOb3RpZmljYXRpb24oJ1NlcnZlciBzZXR0aW5ncyB1cGRhdGVkJywgJ0NoYW5nZXMgd2lsbCBiZSBhcHBsaWVkIG9uIG5leHQgc2VydmVyIHJlc3RhcnQnKTtcblx0XHRcdH1cblx0XHRcdGVsc2Vcblx0XHRcdHtcblx0XHRcdFx0Ly8gU2hvdyBhbGVydFxuXHRcdFx0XHR0aGlzLnNoZWxsQ3RybC5zaG93U2ltcGxlQWxlcnQoYEFkbWluaXN0cmF0b3IgJHt1cGRhdGVyfSBoYXMgbW9kaWZpZWQgdGhlIHNlcnZlciBzZXR0aW5nczsgcGxlYXNlIHJlbG9hZCB0byB1cGRhdGUgeW91ciB2aWV3LmApO1xuXG5cdFx0XHRcdC8vIERpc2FibGUgc3VibWl0IGJ1dHRvblxuXHRcdFx0XHQkKCcjc3JjLXN1Ym1pdEJ1dHRvbicpLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gU2VydmVyIGNvbmZpZ3VyYXRpb24geG1sIHNhdmVkIGJ5IGFuIGV4dGVybmFsIHByb2Nlc3Ncblx0XHRlbHNlIGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9DT05GSUdfQ0hBTkdFRF9BTEVSVClcblx0XHR7XG5cdFx0XHQvLyBTaG93IGFsZXJ0XG5cdFx0XHR0aGlzLnNoZWxsQ3RybC5zaG93U2ltcGxlQWxlcnQoYFRoZSBzeXN0ZW0gaGFzIG1vZGlmaWVkIHRoZSBzZXJ2ZXIgc2V0dGluZ3MgYXV0b21hdGljYWxseTsgcGxlYXNlIHJlbG9hZCB0byB1cGRhdGUgeW91ciB2aWV3LmApO1xuXG5cdFx0XHQvLyBEaXNhYmxlIHN1Ym1pdCBidXR0b25cblx0XHRcdCQoJyNzcmMtc3VibWl0QnV0dG9uJykuYXR0cignZGlzYWJsZWQnLCB0cnVlKTtcblx0XHR9XG5cblx0XHQvLyBTU0wgY2VydGlmaWNhdGUgdXBsb2FkIGVycm9yXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfU1NMX1VQTE9BRF9FUlJPUilcblx0XHR7XG5cdFx0XHRjb25zdCBlcnJvciA9IGRhdGEuZ2V0VXRmU3RyaW5nKCdlcnJvcicpO1xuXG5cdFx0XHQvLyBMb2cgd2FybmluZ1xuXHRcdFx0dGhpcy5zaGVsbEN0cmwubG9nTWVzc2FnZShlcnJvciwgJ2Vycm9yJyk7XG5cblx0XHRcdC8vIFNob3cgZXJyb3IgaW4gbWFuYWdlciB3aW5kb3dcblx0XHRcdHRoaXMuX3NzbENlcnRNYW5hZ2VyLm9uU3NsQ2VydFVwbG9hZEVycm9yKGVycm9yKTtcblx0XHR9XG5cblx0XHQvLyBTU0wgY2VydGlmaWNhdGUgdXBsb2FkIGNvbmZpcm1lZFxuXHRcdGVsc2UgaWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX1NTTF9VUExPQURfQ09ORklSTSlcblx0XHR7XG5cdFx0XHQvLyBDbG9zdyBtYW5hZ2VyIHdpbmRvd1xuXHRcdFx0dGhpcy5fc3NsQ2VydE1hbmFnZXIub25Tc2xDZXJ0VXBsb2FkU3VjY2VzcygpO1xuXG5cdFx0XHRsZXQgdXBkYXRlciA9IGRhdGEuZ2V0VXRmU3RyaW5nKCd1c2VyJyk7XG5cblx0XHRcdC8vIERpc3BsYXkgbm90aWZpY2F0aW9uXG5cdFx0XHRpZiAodXBkYXRlciA9PSB0aGlzLnNtYXJ0Rm94Lm15U2VsZi5uYW1lKVxuXHRcdFx0XHR0aGlzLnNoZWxsQ3RybC5zaG93Tm90aWZpY2F0aW9uKCdTU0wgY2VydGlmaWNhdGUnLCAnU1NMIGNlcnRpZmljYXRlIGtleXN0b3JlIHdhcyB1cGxvYWRlZCBzdWNjZXNzZnVsbHknKTtcblx0XHRcdGVsc2Vcblx0XHRcdFx0dGhpcy5zaGVsbEN0cmwuc2hvd05vdGlmaWNhdGlvbignU1NMIGNlcnRpZmljYXRlJywgYEFkbWluaXN0cmF0b3IgJHt1cGRhdGVyfSBoYXMgdXBsb2FkZWQgYSBuZXcgU1NMIGNlcnRpZmljYXRlIGtleXN0b3JlYCk7XG5cblx0XHRcdC8vIFdoZW4gYSBjZXJ0aWZpY2F0ZSBpcyB1cGxvYWRlZCwgSFRUUFMgaXMgYWxzbyBlbmFibGVkIGF1dG9tYXRpY2FsbHk6XG5cdFx0XHQvLyB3ZSBoYXZlIHRvIHVwZGF0ZSB0aGUgaW50ZXJmYWNlIGFjY29yZGluZ2x5XG5cdFx0XHR0aGlzLl91cGRhdGVDb25maWdGb3JtSXRlbURpc3BsYXllZFZhbHVlKCd3ZWJTZXJ2ZXIuZW5hYmxlSHR0cHMnLCB0cnVlKTtcblx0XHR9XG5cblx0XHQvLyBHZW9sb2NhdGlvbiBkYXRhYmFzZSB1cGRhdGUgY29uZmlybWF0aW9uXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfVVBEQVRFX0dFT19EQilcblx0XHR7XG5cdFx0XHQvLyBFbmFibGUgYnV0dG9uXG5cdFx0XHQkKCcjc3JjLXVwZGF0ZUdlb2xvY0RiQnV0dG9uJykuYXR0cignZGlzYWJsZWQnLCBmYWxzZSk7XG5cblx0XHRcdC8vIENoZWNrIHN1Y2Nlc3Ncblx0XHRcdGlmIChkYXRhLmdldEJvb2woJ3N1Y2Nlc3MnKSlcblx0XHRcdHtcblx0XHRcdFx0Ly8gVXBkYXRlIGRpc3BsYXllZCBkYXRlXG5cdFx0XHRcdHRoaXMuX3VwZGF0ZUNvbmZpZ0Zvcm1JdGVtRGlzcGxheWVkVmFsdWUoJ2FkbWluSGVscGVyLmdlb0RiUmVsZWFzZURhdGUnLCBkYXRhLmdldFV0ZlN0cmluZygnbmV3UmVsRGF0ZScpKTtcblxuXHRcdFx0XHQvLyBJZiB0aGUgY3VycmVudCB1c2VyIGlzIHRoZSB1cGRhdGVyLCBhbHNvIHNob3cgYSBub3RpZmljYXRpb25cblx0XHRcdFx0bGV0IHVwZGF0ZXIgPSBkYXRhLmdldFV0ZlN0cmluZygndXNlcicpO1xuXG5cdFx0XHRcdGlmICh1cGRhdGVyID09IHRoaXMuc21hcnRGb3gubXlTZWxmLm5hbWUpXG5cdFx0XHRcdFx0dGhpcy5zaGVsbEN0cmwuc2hvd05vdGlmaWNhdGlvbignR2VvbG9jYXRpb24gZGF0YWJhc2UgdXBkYXRlZCcsICdMYXRlc3QgcmVsZWFzZSBvZiB0aGUgR2VvTGl0ZTIgQ291bnRyeSBkYXRhYmFzZSBoYXMgYmVlbiBpbnN0YWxsZWQgc3VjY2Vzc2Z1bGx5Jyk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlXG5cdFx0XHR7XG5cdFx0XHRcdC8vIFNob3cgYWxlcnRcblx0XHRcdFx0dGhpcy5zaGVsbEN0cmwuc2hvd1NpbXBsZUFsZXJ0KGRhdGEuZ2V0VXRmU3RyaW5nKCdlcnJvcicpKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBQUklWQVRFIE1FVEhPRFNcblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRfZW5hYmxlQnV0dG9ucyhlbmFibGVkKVxuXHR7XG5cdFx0JCgnI3NyYy1yZWxvYWRCdXR0b24nKS5hdHRyKCdkaXNhYmxlZCcsICFlbmFibGVkKTtcblx0XHQkKCcjc3JjLXN1Ym1pdEJ1dHRvbicpLmF0dHIoJ2Rpc2FibGVkJywgIWVuYWJsZWQpO1xuXHRcdCQoJyNzcmMtYmFja3VwQ2hlY2snKS5hdHRyKCdkaXNhYmxlZCcsICFlbmFibGVkKTtcblxuXHRcdCQoJyNzcmMtdXBkYXRlR2VvbG9jRGJCdXR0b24nKS5hdHRyKCdkaXNhYmxlZCcsICFlbmFibGVkKTtcblxuXHRcdGlmICghdGhpcy5fc3NsTG9ja2VkKVxuXHRcdFx0dGhpcy5fc3NsQ2VydE1hbmFnZXIuZW5hYmxlZCA9IGVuYWJsZWQ7XG5cdH1cblxuXHRfc3dpdGNoVmlldyh2aWV3SWQpXG5cdHtcblx0XHRkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc3JjLXZpZXdzdGFjaycpLnNlbGVjdGVkRWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHZpZXdJZCk7XG5cdH1cblxuXHRfY2xlYXJUYWJzKClcblx0e1xuXHRcdC8vIERlc3Ryb3kgc2Nyb2xsaW5nIHRhYnNcblx0XHQkKCcjc3JjLXRhYk5hdmlnYXRvciAjdGFicycpLnNjcm9sbGluZ1RhYnMoJ2Rlc3Ryb3knKTtcblxuXHRcdC8vIFJlbW92ZSBhbGwgdGFiIG5hdmlnYXRvciBjb250ZW50XG5cdFx0dGhpcy5faW50ZXJmYWNlQnVpbGRlci5kZXN0cm95SW50ZXJmYWNlKCk7XG5cdH1cblxuXHRfb25VcGRhdGVHZW9sb2NEYkNsaWNrKClcblx0e1xuXHRcdC8vIERpc2FibGUgYnV0dG9uXG5cdFx0JCgnI3NyYy11cGRhdGVHZW9sb2NEYkJ1dHRvbicpLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cblx0XHQvLyBTZW5kIHJlcXVlc3QgdG8gc2VydmVyXG5cdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9VUERBVEVfR0VPX0RCKTtcblx0fVxuXG5cdF9vblJlbG9hZENsaWNrKClcblx0e1xuXHRcdC8vIERpc2FibGUgYnV0dG9uc1xuXHRcdHRoaXMuX2VuYWJsZUJ1dHRvbnMoZmFsc2UpO1xuXG5cdFx0Ly8gU3dpdGNoIHRvIGxvYWRpbmcgdmlld1xuXHRcdHRoaXMuX3N3aXRjaFZpZXcoJ3NyYy1sb2FkaW5nJyk7XG5cblx0XHQvLyBIaWRlIHZhbGlkYXRpb24gbWVzc2FnZXNcblx0XHR0aGlzLl9pbnRlcmZhY2VCdWlsZGVyLnJlc2V0VmFsaWRhdGlvbigpO1xuXG5cdFx0Ly8gUmVxdWVzdCBjb25maWd1cmF0aW9uIGRhdGEgdG8gc2VydmVyIGluc3RhbmNlXG5cdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9HRVRfQ09ORklHKTtcblx0fVxuXG5cdF9vblN1Ym1pdENsaWNrKClcblx0e1xuXHRcdC8vIENoZWNrIHZhbGlkaXR5XG5cdFx0aWYgKHRoaXMuX2ludGVyZmFjZUJ1aWxkZXIuY2hlY2tJc1ZhbGlkKCkpXG5cdFx0e1xuXHRcdFx0bGV0IGNoYW5nZXMgPSB0aGlzLl9pbnRlcmZhY2VCdWlsZGVyLmdldENoYW5nZWREYXRhKCk7XG5cblx0XHRcdGlmIChjaGFuZ2VzLnNpemUoKSA+IDApXG5cdFx0XHR7XG5cdFx0XHRcdC8vIERpc2FibGUgYnV0dG9uc1xuXHRcdFx0XHR0aGlzLl9lbmFibGVCdXR0b25zKGZhbHNlKTtcblxuXHRcdFx0XHQvLyBEaXNhYmxlIGZvcm0gaXRlbXNcblx0XHRcdFx0dGhpcy5faW50ZXJmYWNlQnVpbGRlci5kaXNhYmxlSW50ZXJmYWNlKHRydWUpO1xuXG5cdFx0XHRcdC8vIFNlbmQgdXBkYXRlZCBzZXR0aW5ncyB0byBzZXJ2ZXIgaW5zdGFuY2Vcblx0XHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblx0XHRcdFx0cGFyYW1zLnB1dFNGU0FycmF5KCdzZXR0aW5ncycsIGNoYW5nZXMpO1xuXHRcdFx0XHRwYXJhbXMucHV0Qm9vbCgnYmFja3VwJywgJCgnI3NyYy1iYWNrdXBDaGVjaycpLnByb3AoJ2NoZWNrZWQnKSk7XG5cblx0XHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9VUERBVEVfQ09ORklHLCBwYXJhbXMpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRlbHNlXG5cdFx0XHR0aGlzLnNoZWxsQ3RybC5zaG93U2ltcGxlQWxlcnQoJ1VuYWJsZSB0byBzdWJtaXQgY29uZmlndXJhdGlvbiBjaGFuZ2VzIGR1ZSB0byBhbiBpbnZhbGlkIHZhbHVlOyBwbGVhc2UgdmVyaWZ5IHRoZSBoaWdobGlnaHRlZCBmb3JtIGZpZWxkcyBpbiBhbGwgdGFicy4nLCB0cnVlKTtcblx0fVxuXG5cdF91cGRhdGVDb25maWdGb3JtSXRlbURpc3BsYXllZFZhbHVlKGNvbmZpZ1BhcmFtTmFtZSwgbmV3VmFsdWUpXG5cdHtcblx0XHQvLyBHZXQgdGhlIHJlbGV2YW50IENvbmZpZ3VyYXRpb24gRm9ybSBJdGVtXG5cdFx0Y29uc3QgY29uZmlnRm9ybUl0ZW0gPSB0aGlzLl9pbnRlcmZhY2VCdWlsZGVyLmdldENvbmZpZ0Zvcm1JdGVtKGNvbmZpZ1BhcmFtTmFtZSk7XG5cblx0XHQvLyBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgYXNzb2NpYXRlZCB3aXRoIHRoZSBDb25maWd1cmF0aW9uIEZvcm0gSXRlbVxuXHRcdGNvbmZpZ0Zvcm1JdGVtLmRhdGEudmFsdWUgPSBuZXdWYWx1ZTtcblx0XHRjb25maWdGb3JtSXRlbS5kYXRhLnJlc2V0SXNNb2RpZmllZCgpOyAvLyBUaGlzIGlzIG5lZWRlZCB0byBhdm9pZCB0aGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdG8gZmxhZ2dlZCBhcyAnY2hhbmdlZCdcblxuXHRcdC8vIERpc3BsYXkgdGhlIG5ldyB2YWx1ZSBvZiB0aGUgQ29uZmlndXJhdGlvbiBGb3JtIEl0ZW1cblx0XHRjb25maWdGb3JtSXRlbS5fc2V0V2lkZ2V0VmFsdWUoKTsgLy8gRGlzcGxheSB0aGUgbmV3IHZhbHVlIGluIHRoZSBjb25maWcgZm9ybSBpdGVtXG5cdH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQ25kQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7QSIsInNvdXJjZVJvb3QiOiIifQ==
768
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtOS5idW5kbGUuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9tb2R1bGVzL2V4dGVuc2lvbi1kZXBsb3llci5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0Jhc2VNb2R1bGV9IGZyb20gJy4vYmFzZS1tb2R1bGUnO1xuaW1wb3J0ICogYXMgbW9tZW50IGZyb20gJ21vbWVudCc7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEV4dGVuc2lvbkRlcGxveWVyIGV4dGVuZHMgQmFzZU1vZHVsZVxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKCdleHREZXBsb3llcicpO1xuXG5cdFx0Ly8gT3V0Z29pbmcgcmVxdWVzdHNcblx0XHR0aGlzLlJFUV9JTklUID0gJ2luaXQnO1xuXHRcdHRoaXMuUkVRX0dFVF9OT0RFUyA9ICdnZXROb2Rlcyc7XG5cblx0XHQvLyBJbmNvbWluZyByZXNwb25zZXNcblx0XHR0aGlzLlJFU1BfTE9DS0VEID0gJ2xvY2snO1xuXHRcdHRoaXMuUkVTUF9JTklUID0gJ2luaXQnO1xuXHRcdHRoaXMuUkVTUF9OT0RFUyA9ICdub2Rlcyc7XG5cdFx0dGhpcy5SRVNQX1NVQ0NFU1MgPSAnc3VjY2Vzcyc7XG5cdFx0dGhpcy5SRVNQX1dBUk4gPSAnd2Fybic7XG5cdFx0dGhpcy5SRVNQX0VSUk9SID0gJ2Vycm9yJztcblxuXHRcdHRoaXMuX3NlbGVjdGVkTm9kZXMgPSBbXTtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIENPTU1PTiBNT0RVTEUgSU5URVJGQUNFIE1FVEhPRFNcblx0Ly8gVGhpcyBtZW1iZXJzIGFyZSB1c2VkIGJ5IHRoZSBtYWluIGNvbnRyb2xsZXJcblx0Ly8gdG8gY29tbXVuaWNhdGUgd2l0aCB0aGUgbW9kdWxlJ3MgY29udHJvbGxlci5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRpbml0aWFsaXplKGlkRGF0YSwgc2hlbGxDb250cm9sbGVyKVxuXHR7XG5cdFx0Ly8gQ2FsbCBzdXBlciBtZXRob2Rcblx0XHRzdXBlci5pbml0aWFsaXplKGlkRGF0YSwgc2hlbGxDb250cm9sbGVyKTtcblxuXHRcdC8vIEluaXRpYWxpemUgcHJvZ3Jlc3MgYmFyc1xuXHRcdCQoJy5leGQtcHJvZ3Jlc3NCYXInKS5rZW5kb1Byb2dyZXNzQmFyKHtcblx0XHRcdG1pbjogMCxcbiAgICAgICAgICAgIG1heDogMTAwLFxuXHRcdFx0dmFsdWU6IGZhbHNlLFxuICAgICAgICAgICAgdHlwZTogJ3ZhbHVlJyxcbiAgICAgICAgICAgIGFuaW1hdGlvbjoge1xuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiA0MDBcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXJzIHRvIGJ1dHRvbnNcblx0XHQkKCcjZXhkLXJldHJ5QnQnKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uUmV0cnlDbGljaywgdGhpcykpO1xuXHRcdCQoJyNleGQtcmVmcmVzaEJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9yZXF1ZXN0Tm9kZXNMaXN0LCB0aGlzKSk7XG5cdFx0JCgnI2V4ZC1kZXBsb3lCdCcpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25EZXBsb3lDbGljaywgdGhpcykpO1xuXHRcdCQoJy5leGQtc3RhdHVzQ2xvc2VCdCcpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25DbG9zZVN0YXR1c0NsaWNrLCB0aGlzKSk7XG5cblx0XHQvLyBJbml0aWFsaXplIGtlbmRvIHN3aXRjaFxuXHRcdHRoaXMuX21vZGVTd2l0Y2ggPSAkKCcjZXhkLW1vZGVDYicpLmtlbmRvU3dpdGNoKCkuZGF0YSgna2VuZG9Td2l0Y2gnKTtcblxuXHRcdC8vIEluaXRpYWxpemUgZ3JpZFxuXHRcdHRoaXMuX2dyaWQgPSAkKCcjZXhkLW5vZGVzTGlzdCcpLmtlbmRvR3JpZCh7XG5cdFx0XHRzY3JvbGxhYmxlOiB0cnVlLFxuICAgICAgICAgICAgc29ydGFibGU6IHRydWUsXG5cdFx0XHQvL3Jlc2l6YWJsZTogdHJ1ZSxcblx0XHRcdHNlbGVjdGFibGU6IGZhbHNlLFxuICAgICAgICAgICAgY29sdW1uczogW1xuXHRcdFx0XHR7XG5cdFx0XHRcdFx0c2VsZWN0YWJsZTogdHJ1ZSxcblx0XHRcdFx0XHR3aWR0aDogNDFcblx0XHRcdFx0fSxcblx0XHRcdFx0e1xuXHQgICAgICAgICAgICAgICAgZmllbGQ6ICduYW1lJyxcblx0ICAgICAgICAgICAgICAgIHdpZHRoOiA1MDAsXG5cdFx0XHRcdFx0dGl0bGU6ICdOb2RlJyxcblx0XHRcdFx0XHR0ZW1wbGF0ZTogZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRcdFx0XHRcdGlmIChkYXRhSXRlbVsnYWxpYXMnXSlcblx0XHRcdFx0XHRcdFx0cmV0dXJuICc8ZGl2IGNsYXNzPVwibmFtZS1jZWxsXCI+PHNwYW4+JyArIGRhdGFJdGVtWydhbGlhcyddICsgJzwvc3Bhbj48YnI+PHNtYWxsIGNsYXNzPVwidGV4dC1tdXRlZFwiPicgKyBkYXRhSXRlbVsnbmFtZSddICsgJzxzbWFsbD48L2Rpdj4nO1xuXHRcdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gJzxkaXYgY2xhc3M9XCJuYW1lLWNlbGxcIj48c3Bhbj4nICsgZGF0YUl0ZW1bJ25hbWUnXSArICc8L3NwYW4+PC9kaXY+Jztcblx0XHRcdFx0XHR9XG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdHtcblx0ICAgICAgICAgICAgICAgIGZpZWxkOiAnaGVhbHRoJyxcblx0ICAgICAgICAgICAgICAgIHdpZHRoOiA3NSxcblx0XHRcdFx0XHR0aXRsZTogJ0hlYWx0aCcsXG5cdFx0XHRcdFx0c29ydGFibGU6IGZhbHNlLFxuXHRcdFx0XHRcdHRlbXBsYXRlOiAkLnByb3h5KHRoaXMuX2dldEhlYWx0aFRlbXBsYXRlLCB0aGlzKVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XSxcblx0XHRcdG5vUmVjb3Jkczoge1xuXHRcdFx0XHR0ZW1wbGF0ZTogJ05vIGdhbWUgbm9kZXMgaW4gdGhlIGNsdXN0ZXIuJ1xuXHRcdFx0fSxcblx0XHRcdGRhdGFTb3VyY2U6IHtcblx0XHRcdFx0c2NoZW1hOiB7XG5cdFx0XHRcdFx0bW9kZWw6IHtcblx0XHRcdFx0XHRcdGlkOiAnaWQnLFxuXHRcdFx0XHRcdFx0Ly8gZmllbGRzOiB7XG5cdFx0XHRcdFx0XHQvLyBcdGlkOiB7IHR5cGU6ICdzdHJpbmcnIH0sXG5cdFx0XHRcdFx0XHQvLyBcdGFjdGl2ZTogeyB0eXBlOiAnYm9vbGVhbicgfVxuXHRcdFx0XHRcdFx0Ly8gfVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSxcblx0XHRcdFx0Z3JvdXA6IHtcblx0XHRcdFx0XHRmaWVsZDogJ2FjdGl2ZScsXG5cdFx0XHRcdFx0ZGlyOiAnZGVzYycsXG5cdFx0XHRcdH1cbiAgICAgICAgICAgIH0sXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25Ob2Rlc0dyaWRDaGFuZ2UsIHRoaXMpLFxuXHRcdFx0ZGF0YUJvdW5kOiAkLnByb3h5KHRoaXMuX29uTm9kZXNHcmlkRGF0YUJvdW5kLCB0aGlzKSxcbiAgICAgICAgfSkuZGF0YSgna2VuZG9HcmlkJyk7XG5cblx0XHQvLyBJbml0aWFsaXplIGtlbmRvIHVwbG9hZGVyXG5cdFx0dGhpcy5fdXBsb2FkZXIgPSAkKCcjZXhkLXVwbG9hZGVyJykua2VuZG9VcGxvYWQoe1xuXHRcdFx0bXVsdGlwbGU6IGZhbHNlLFxuXHRcdFx0YXN5bmM6IHtcblx0XHRcdFx0c2F2ZVVybDogJ2h0dHA6Ly9sb2NhbGhvc3QnLCAvLyBUaGlzIHdpbGwgYmUgY2hhbmdlZCBsYXRlciBpbiBfb25VcGxvYWRTdGFydCBtZXRob2Rcblx0XHRcdFx0YXV0b1VwbG9hZDogZmFsc2UsXG5cdFx0XHR9LFxuXHRcdFx0ZGlyZWN0b3J5RHJvcDogdHJ1ZSxcblx0XHRcdHVwbG9hZDogJC5wcm94eSh0aGlzLl9vblVwbG9hZFN0YXJ0LCB0aGlzKSxcblx0XHRcdGNvbXBsZXRlOiAkLnByb3h5KHRoaXMuX29uVXBsb2FkRW5kLCB0aGlzKSxcblx0XHRcdGxvY2FsaXphdGlvbjoge1xuXHRcdFx0XHRzZWxlY3Q6ICdTZWxlY3QgemlwIGZpbGUuLi4nXG5cdFx0XHR9XG5cdFx0fSkuZGF0YSgna2VuZG9VcGxvYWQnKTtcblxuXHRcdC8vIEluaXRpYWxpemUgXCJkZXBsb3ltZW50IHN0YXR1c1wiIG1vZGFsXG5cdFx0dGhpcy5fZGVwbG95U3RhdHVzTW9kYWwgPSAkKCcjZXhkLWRlcGxveVN0YXR1c01vZGFsJyk7XG5cdFx0dGhpcy5fZGVwbG95U3RhdHVzTW9kYWwubW9kYWwoe1xuXHRcdFx0YmFja2Ryb3A6ICdzdGF0aWMnLFxuXHRcdFx0a2V5Ym9hcmQ6IGZhbHNlLFxuXHRcdFx0c2hvdzogZmFsc2Vcblx0XHR9KTtcblxuXHRcdC8vIEluaXRpYWxpemUgaGVscCB0b29sdGlwc1xuXHRcdCQodGhpcykua2VuZG9Ub29sdGlwKHtcblx0XHRcdGZpbHRlcjogJ2lbdGl0bGVdLmhlbHAnLFxuXHRcdFx0cG9zaXRpb246ICdyaWdodCcsXG5cdFx0XHRjb250ZW50OiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdHJldHVybiBgPGRpdiBjbGFzcz1cImhlbHAtdG9vbHRpcFwiPiR7ZS50YXJnZXQuZGF0YSgndGl0bGUnKX08L2Rpdj5gO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Ly8gU2V0IHVwbG9hZCBmb3JtIGRpc2FibGVkXG5cdFx0dGhpcy5fZW5hYmxlRGVwbG95Rm9ybShmYWxzZSk7XG5cblx0XHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRcdC8vIFNlbmQgaW5pdGlhbGl6YXRpb24gcmVxdWVzdFxuXHRcdHRoaXMuc2VuZEV4dGVuc2lvblJlcXVlc3QodGhpcy5SRVFfSU5JVCk7XG5cdH1cblxuXHRkZXN0cm95KClcblx0e1xuXHRcdC8vIENhbGwgc3VwZXIgbWV0aG9kXG5cdFx0c3VwZXIuZGVzdHJveSgpO1xuXG5cdFx0Ly8gUmVtb3ZlIGNsaWNrIGxpc3RlbmVyc1xuXHRcdCQoJyNleGQtcmV0cnlCdCcpLm9mZignY2xpY2snKTtcblx0XHQkKCcjZXhkLXJlZnJlc2hCdCcpLm9mZignY2xpY2snKTtcblx0XHQkKCcjZXhkLWRlcGxveUJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJy5leGQtc3RhdHVzQ2xvc2VCdCcpLm9mZignY2xpY2snKTtcblxuXHRcdC8vIENsZWFyIG5vZGVzIHJlcXVlc3Qgc2NoZWR1bGluZ1xuXHRcdGNsZWFyVGltZW91dCh0aGlzLl9yZXF1ZXN0Tm9kZXNUaW1lcik7XG5cdH1cblxuXHRvbkV4dGVuc2lvbkNvbW1hbmQoY29tbWFuZCwgZGF0YSlcblx0e1xuXHRcdC8qXG5cdFx0ICogVGhpcyByZXNwb25zZSBpcyByZXR1cm5lZCBpZiB0aGUgZmlsZSBVcGxvYWRzTG9jay50eHQgZXhpc3RzIGluIHRoZSAvY29uZmlnIGZvbGRlciBvZiB0aGUgc2VydmVyLlxuXHRcdCAqIFRoaXMgaXMgYW4gYWRkaXRpb25hbCBzZWN1cml0eSBtZWFzdXJlIHRvIGF2b2lkIHVud2FudGVkIGZpbGVzIHRvIGJlIHVwbG9hZGVkIGJ5IG1hbGljaXVzIHVzZXJzIGFjY2Vzc2luZyB0aGUgc2VydmVyXG5cdFx0ICogd2l0aCB0aGUgZGVmYXVsdCBjcmVkZW50aWFscywgaW4gY2FzZSB0aGV5IGhhdmUgbm90IGJlZW4gY2hhbmdlZCBieSB0aGUgYWRtaW5pc3RyYXRvciBhZnRlciB0aGUgaW5zdGFsbGF0aW9uLlxuXHRcdCAqIFRoZSBmaWxlIG11c3QgYmUgcmVtb3ZlZCBtYW51YWxseSBiZWZvcmUgYWNjZXNzaW5nIHRoZSBFeHRlbnNpb24gRGVwbG95ZXIgbW9kdWxlIGZvciB0aGUgZmlyc3QgdGltZVxuXHRcdCAqL1xuXHRcdGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9MT0NLRUQpXG5cdFx0e1xuXHRcdFx0Ly8gU2hvdyB3YXJuaW5nXG5cdFx0XHR0aGlzLl9zd2l0Y2hNYWluVmlldygnZXhkLWxvY2tlZCcpO1xuXHRcdH1cblxuXHRcdC8vIE1vZHVsZSBjYW4gYmUgZW5hYmxlZCAobm8gbG9ja2luZyBmaWxlIGV4aXN0cylcblx0XHRlbHNlIGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9JTklUKVxuXHRcdHtcblx0XHRcdC8vIFJldHJpZXZlIG1vZHVsZSBpZCBzZW50IGJ5IHRoZSBzZXJ2ZXIgKHJlcXVpcmVkIGJlY2F1c2UgbXVsdGlwbGUgbW9kdWxlcyB1c2UgZmlsZSB1cGxvYWRpbmcgc2VydmljZSlcblx0XHRcdGNvbnN0IHVwbG9hZE1vZHVsZUlkID0gZGF0YS5nZXRVdGZTdHJpbmcoJ21vZElkJyk7XG5cblx0XHRcdC8vIFNldCBmaWxlIHVwbG9hZGluZyB0YXJnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0dGhpcy5fdXBsb2FkVGFyZ2V0Q29uZmlnID0ge1xuXHRcdFx0XHRzZXNzaW9uVG9rZW46IHRoaXMuc21hcnRGb3guc2Vzc2lvblRva2VuLFxuXHRcdFx0XHRob3N0OiB0aGlzLnNtYXJ0Rm94LmNvbmZpZy5ob3N0LFxuXHRcdFx0XHRwb3J0OiB0aGlzLnNtYXJ0Rm94LmNvbmZpZy5wb3J0LFxuXHRcdFx0XHRtb2R1bGVJZDogdXBsb2FkTW9kdWxlSWQsXG5cdFx0XHRcdHByb3RvY29sOiB0aGlzLnNtYXJ0Rm94LmNvbmZpZy51c2VTU0wgPyAnaHR0cHMnIDogJ2h0dHAnXG5cdFx0XHR9O1xuXG5cdFx0XHQvLyBTaG93IG1vZHVsZSdzIG1haW4gdmlld1xuXHRcdFx0dGhpcy5fc3dpdGNoTWFpblZpZXcoJ2V4ZC1tYWluJyk7XG5cblx0XHRcdC8vIFJlcXVlc3Qgbm9kZXMgbGlzdCB0byBzZXJ2ZXJcblx0XHRcdHRoaXMuX3JlcXVlc3ROb2Rlc0xpc3QoKTtcblx0XHR9XG5cblx0XHRlbHNlIGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9OT0RFUylcblx0XHR7XG5cdFx0XHRsZXQgbm9kZXNPYmogPSBkYXRhLmdldFNGU0FycmF5KCdub2RlcycpO1xuXG5cdFx0XHRsZXQgbm9kZXMgPSBbXTtcblx0XHRcdGxldCBub2Rlc0lkcyA9IFtdO1xuXG5cdFx0XHRmb3IgKGxldCBpID0gMDsgaSA8IG5vZGVzT2JqLnNpemUoKTsgaSsrKVxuXHRcdFx0e1xuXHRcdFx0XHRsZXQgbm9kZSA9IG5vZGVzT2JqLmdldFNGU0FycmF5KGkpO1xuXG5cdFx0XHRcdG5vZGVzSWRzLnB1c2gobm9kZS5nZXRVdGZTdHJpbmcoMCkpO1xuXG5cdFx0XHRcdG5vZGVzLnB1c2goe1xuXHRcdFx0XHRcdCdpZCc6IG5vZGUuZ2V0VXRmU3RyaW5nKDApLFxuXHRcdFx0XHRcdCdhbGlhcyc6IG5vZGUuZ2V0VXRmU3RyaW5nKDEpLFxuXHRcdFx0XHRcdCduYW1lJzogbm9kZS5nZXRVdGZTdHJpbmcoMiksXG5cdFx0XHRcdFx0J2hlYWx0aCc6IG5vZGUuZ2V0Qm9vbCgzKSxcblx0XHRcdFx0XHQnYWN0aXZlJzogbm9kZS5nZXRCb29sKDQpLCAvLyBVc2VkIGZvciBncm91cGluZ1xuXHRcdFx0XHR9KTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gR2V0IG5vZGVzIGdyaWQgZGF0YXNvdXJjZVxuXHRcdFx0bGV0IGRzID0gdGhpcy5fZ3JpZC5kYXRhU291cmNlO1xuXG5cdFx0XHQvLyAtLS0gUkVNT1ZFIE5PREVTIC0tLVxuXG5cdFx0XHRsZXQgc2VsZiA9IHRoaXM7XG5cdFx0XHQkLm1hcChkcy5kYXRhKCksIGZ1bmN0aW9uIChkYXRhSXRlbSwgaW5kZXgpIHtcblx0XHRcdFx0aWYgKGRhdGFJdGVtICYmICFub2Rlc0lkcy5pbmNsdWRlcyhkYXRhSXRlbVsnaWQnXSkpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHQvLyBSZW1vdmUgbm9kZSBmcm9tIGRhdGFzdG9yZVxuXHRcdFx0XHRcdGRzLnJlbW92ZShkYXRhSXRlbSk7XG5cblx0XHRcdFx0XHQvLyBSZW1vdmUgbm9kZSBmcm9tIGxpc3Qgb2Ygc2VsZWN0ZWQgbm9kZXMgKGlmIHNlbGVjdGVkKVxuXHRcdFx0XHRcdHNlbGYuX3NlbGVjdGVkTm9kZXMgPSBzZWxmLl9zZWxlY3RlZE5vZGVzLmZpbHRlcih4ID0+IHggIT09IGRhdGFJdGVtWydpZCddKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cblx0XHRcdC8vIC0tLSBBREQvVVBEQVRFIE5PREVTIC0tLVxuXG5cdFx0XHRmb3IgKGxldCBub2RlIG9mIG5vZGVzKVxuXHRcdFx0e1xuXHRcdFx0XHR2YXIgZGF0YUl0ZW0gPSBkcy5nZXQobm9kZS5pZCk7XG5cblx0XHRcdFx0Ly8gVXBkYXRlIG5vZGVcblx0XHRcdFx0aWYgKGRhdGFJdGVtKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0ZGF0YUl0ZW0uc2V0KCdoZWFsdGgnLCBub2RlLmhlYWx0aCk7XG5cdFx0XHRcdFx0ZGF0YUl0ZW0uc2V0KCdhY3RpdmUnLCBub2RlLmFjdGl2ZSk7XG5cblx0XHRcdFx0XHRkYXRhSXRlbS5kaXJ0eSA9IGZhbHNlOyAvLyBIaWRlcyBcImRpcnR5XCIgaW5kaWNhdG9yIGluIGdyaWRcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEFkZCBub2RlXG5cdFx0XHRcdGVsc2Vcblx0XHRcdFx0IFx0ZHMuYWRkKG5vZGUpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBSZWZyZXNoIGdyaWRcblx0XHRcdHRoaXMuX2dyaWQucmVmcmVzaCgpO1xuXHRcdH1cblxuXHRcdGVsc2UgaWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX0VSUk9SKVxuXHRcdHtcblx0XHRcdC8vIERpc3BsYXkgZXJyb3IgbWVzc2FnZVxuXHRcdFx0JCgnI2V4ZC1zdGF0dXNFcnJvclRleHQnKS5odG1sKGRhdGEuZ2V0VXRmU3RyaW5nKCdtc2cnKSk7XG5cblx0XHRcdC8vIFN3aXRjaCB0byB2aWV3XG5cdFx0XHR0aGlzLl9zd2l0Y2hTdGF0dXNWaWV3KCdleGQtc3RhdHVzRXJyb3InKTtcblx0XHR9XG5cblx0XHRlbHNlIGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9XQVJOKVxuXHRcdHtcblx0XHRcdC8vIERpc3BsYXkgZXJyb3IgbWVzc2FnZVxuXHRcdFx0JCgnI2V4ZC1zdGF0dXNXYXJuaW5nVGV4dCcpLmh0bWwoZGF0YS5nZXRVdGZTdHJpbmcoJ21zZycpLnJlcGxhY2UoLyg/OlxcclxcbnxcXHJ8XFxuKS9nLCAnPGJyPicpKTtcblxuXHRcdFx0Ly8gU3dpdGNoIHRvIHZpZXdcblx0XHRcdHRoaXMuX3N3aXRjaFN0YXR1c1ZpZXcoJ2V4ZC1zdGF0dXNXYXJuaW5nJyk7XG5cdFx0fVxuXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfU1VDQ0VTUylcblx0XHR7XG5cdFx0XHR0aGlzLl9zd2l0Y2hTdGF0dXNWaWV3KCdleGQtc3RhdHVzU3VjY2VzcycpO1xuXHRcdH1cblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFVJIEVWRU5UIExJU1RFTkVSU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdF9lbmFibGVEZXBsb3lGb3JtKGVuYWJsZWQpXG5cdHtcblx0XHQkKCcjZXhkLXVwbG9hZEZpbGVGb3JtJykucHJvcCgnZGlzYWJsZWQnLCAhZW5hYmxlZCk7XG5cdFx0dGhpcy5fbW9kZVN3aXRjaC5lbmFibGUoZW5hYmxlZCk7XG5cdH1cblxuXHRfb25SZXRyeUNsaWNrKClcblx0e1xuXHRcdHRoaXMuX3N3aXRjaE1haW5WaWV3KCdleGQtaW5pdCcpO1xuXG5cdFx0Ly8gUmUtc2VuZCBpbml0aWFsaXphdGlvbiByZXF1ZXN0XG5cdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9JTklUKTtcblx0fVxuXG5cdF9vbkNsb3NlU3RhdHVzQ2xpY2soKVxuXHR7XG5cdFx0dGhpcy5fZGVwbG95U3RhdHVzTW9kYWwuaGlkZSgpO1xuXG5cdFx0Ly8gQ2xlYXIgdXBsb2FkZXJcblx0XHR0aGlzLl91cGxvYWRlci5jbGVhckFsbEZpbGVzKCk7XG5cdH1cblxuXHRfb25Ob2Rlc0dyaWRDaGFuZ2UoZSwgYXJncylcblx0e1xuXHRcdGxldCBncmlkID0gZS5zZW5kZXI7XG5cdFx0bGV0IGl0ZW1zID0gZ3JpZC5pdGVtcygpO1xuXG5cdFx0dGhpcy5fc2VsZWN0ZWROb2RlcyA9IFtdO1xuXG5cdFx0Zm9yIChsZXQgaSBvZiBncmlkLnNlbGVjdCgpKVxuXHRcdHtcblx0XHRcdGxldCBkYXRhSXRlbSA9IGdyaWQuZGF0YUl0ZW0oaSk7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZE5vZGVzLnB1c2goZGF0YUl0ZW1bJ2lkJ10pO1xuXHRcdH1cblxuXHRcdC8vIEVuYWJsZSB1cGxvYWQgYnV0dG9uXG5cdFx0dGhpcy5fZW5hYmxlRGVwbG95Rm9ybSh0aGlzLl9zZWxlY3RlZE5vZGVzLmxlbmd0aCA+IDApO1xuXHR9XG5cblx0X29uTm9kZXNHcmlkRGF0YUJvdW5kKGUpXG5cdHtcblx0XHRsZXQgZ3JpZCA9IGUuc2VuZGVyO1xuXHRcdGxldCBpdGVtcyA9IGdyaWQuaXRlbXMoKTtcblx0XHRsZXQgaXRlbXNUb1NlbGVjdCA9IFtdO1xuXHRcdGxldCBzZWxmID0gdGhpcztcblxuXHRcdGl0ZW1zLmVhY2goZnVuY3Rpb24gKGlkeCwgcm93KSB7XG5cdFx0XHRsZXQgZGF0YUl0ZW0gPSBncmlkLmRhdGFJdGVtKHJvdyk7XG5cdFx0XHRpZiAoc2VsZi5fc2VsZWN0ZWROb2Rlcy5pbmNsdWRlcyhkYXRhSXRlbVsnaWQnXSkpIHtcblx0XHRcdCBcdGl0ZW1zVG9TZWxlY3QucHVzaChyb3cpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0Ly8gUmUtc2VsZWN0IHByZXZpb3VzbHkgc2VsZWN0ZWQgbm9kZXNcblx0XHRncmlkLnNlbGVjdChpdGVtc1RvU2VsZWN0KTtcblxuXHRcdC8vIERpc2FibGUgdXBsb2FkIGJ1dHRvblxuXHRcdGlmIChpdGVtc1RvU2VsZWN0Lmxlbmd0aCA9PSAwKVxuXHRcdFx0dGhpcy5fZW5hYmxlRGVwbG95Rm9ybShmYWxzZSk7XG5cblx0XHQvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cblx0XHQvLyBIaWRlIGdyb3VwIGNvbHVtbiBhbmQgY29sbGFwc2UgaWNvblxuXHRcdCQoJyNleGQtbm9kZXNMaXN0IC5rLWdyb3VwLWNvbCwgI2V4ZC1ub2Rlc0xpc3QgLmstZ3JvdXAtY2VsbCcpLnJlbW92ZSgpO1xuXHRcdGxldCBzcGFuQ2VsbHMgPSAkKCcjZXhkLW5vZGVzTGlzdCAuay1ncm91cGluZy1yb3cnKS5jaGlsZHJlbigndGQnKTtcblx0XHRzcGFuQ2VsbHMuYXR0cignY29sc3BhbicsIHNwYW5DZWxscy5hdHRyKCdjb2xzcGFuJykgLSAxKTtcblx0XHQkKCcjZXhkLW5vZGVzTGlzdCAuay1pY29uLmstaS1jb2xsYXBzZScpLmhpZGUoKTtcblxuXHRcdC8vIE1vZGlmeSBncm91cCBsYWJlbFxuXHRcdCQoJyNleGQtbm9kZXNMaXN0IC5rLWdyb3VwaW5nLXJvdyB0ZCBwLmstcmVzZXQnKS5lYWNoKGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHRcdGlmICgkKHRoaXMpLnRleHQoKSA9PSAnYWN0aXZlOiB0cnVlJylcblx0XHRcdFx0JCh0aGlzKS50ZXh0KCdBY3RpdmUgbm9kZXMnKTtcblx0XHRcdGVsc2Vcblx0XHRcdFx0JCh0aGlzKS50ZXh0KCdJbmFjdGl2ZSBub2RlcycpO1xuXHRcdH0pO1xuXHR9XG5cblx0X3JlcXVlc3ROb2Rlc0xpc3QoKVxuXHR7XG5cdFx0Ly8gQ2xlYXIgcHJldmlvdXMgcmVxdWVzdCBzY2hlZHVsaW5nXG5cdFx0Y2xlYXJUaW1lb3V0KHRoaXMuX3JlcXVlc3ROb2Rlc1RpbWVyKTtcblxuXHRcdC8vIENoZWNrIGlmIGNvbm5lY3Rpb24gaXMgc3RpbGwgYXZhaWxhYmxlXG5cdFx0aWYgKHRoaXMuc21hcnRGb3guaXNDb25uZWN0ZWQpXG5cdFx0e1xuXHRcdFx0Ly8gU2VuZCByZXF1ZXN0IHRvIGV4dGVuc2lvblxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9HRVRfTk9ERVMpO1xuXG5cdFx0XHQvLyBTY2hlZHVsZSBuZXh0IHJlcXVlc3Rcblx0XHRcdHRoaXMuX3JlcXVlc3ROb2Rlc1RpbWVyID0gc2V0VGltZW91dCgkLnByb3h5KHRoaXMuX3JlcXVlc3ROb2Rlc0xpc3QsIHRoaXMpLCA1MDAwKTsgLy8gRXZlcnkgNSBzZWNvbmRzXG5cdFx0fVxuXHR9XG5cblx0X29uRGVwbG95Q2xpY2soKVxuXHR7XG5cdFx0Ly8gVHJpZ2dlciBjbGljayBvbiBVcGxvYWQgd2lkZ2V0XG5cdFx0JCgnYnV0dG9uLmstdXBsb2FkLXNlbGVjdGVkJykuY2xpY2soKTtcblx0fVxuXG5cdF9vblVwbG9hZFN0YXJ0KGUpXG5cdHtcblx0XHQvLyBEaXNwbGF5IHN0YXR1cyBtb2RhbFxuXHRcdHRoaXMuX3N3aXRjaFN0YXR1c1ZpZXcoJ2V4ZC1zdGF0dXNQcm9ncmVzcycpO1xuXHRcdHRoaXMuX2RlcGxveVN0YXR1c01vZGFsLnNob3coKTtcblxuXHRcdC8vIFNldCBkZXN0aW5hdGlvbiB1cmxcblx0XHRjb25zdCB1cmwgPSB0aGlzLl91cGxvYWRUYXJnZXRDb25maWcucHJvdG9jb2wgKyAnOi8vJyArIHRoaXMuX3VwbG9hZFRhcmdldENvbmZpZy5ob3N0ICsgJzonICsgdGhpcy5fdXBsb2FkVGFyZ2V0Q29uZmlnLnBvcnQgKyAnL0JsdWVCb3gvU0ZTMlhGaWxlVXBsb2FkP3Nlc3NIYXNoSWQ9JyArIHRoaXMuX3VwbG9hZFRhcmdldENvbmZpZy5zZXNzaW9uVG9rZW47XG5cblx0XHRlLnNlbmRlci5vcHRpb25zLmFzeW5jLnNhdmVVcmwgPSB1cmw7XG5cblx0XHQvLyBTZXQgcGF5bG9hZFxuXHRcdGNvbnN0IHBhcmFtcyA9IG5ldyBGb3JtRGF0YSgpO1xuXHRcdHBhcmFtcy5hcHBlbmQoJ19fbW9kdWxlJywgdGhpcy5fdXBsb2FkVGFyZ2V0Q29uZmlnLm1vZHVsZUlkKTtcblx0XHRwYXJhbXMuYXBwZW5kKCdfX25vZGVzJywgSlNPTi5zdHJpbmdpZnkodGhpcy5fc2VsZWN0ZWROb2RlcykpO1xuXHRcdHBhcmFtcy5hcHBlbmQoJ19fbm9EZXN0cm95JywgdGhpcy5fbW9kZVN3aXRjaC5jaGVjaygpKTtcblxuXHRcdGZvciAobGV0IGYgPSAwOyBmIDwgZS5maWxlcy5sZW5ndGg7IGYrKylcblx0XHRcdHBhcmFtcy5hcHBlbmQoJ2ZpbGVzW10nLCBlLmZpbGVzW2ZdLnJhd0ZpbGUpO1xuXG5cdFx0ZS5mb3JtRGF0YSA9IHBhcmFtcztcblx0fVxuXG5cdF9vblVwbG9hZEVuZChlKVxuXHR7XG5cdFx0Ly8gTm90aGlnbiB0byBkb1xuXHR9XG5cblx0X29uRmlsZXNVcGxvYWRFbmQocmVzcG9uc2UpXG5cdHtcblx0XHQvLyBOb3RoaW5nIHRvIGRvOiB3ZSBoYXZlIHRvIHdhaXQgdGhlIHVwbG9hZCBwcm9jZXNzIGNvbXBsZXRpb24gdG8gYmUgc2lnbmFsZWQgYnkgdGhlIHNlcnZlciB0aHJvdWdoIHRoZSBkZWRpY2F0ZWQgRXh0ZW5zaW9uIHJlc3BvbnNlXG5cblx0XHQvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cblx0XHQvLyBUT0RPIFNob3VsZCB3ZSBoYW5kbGUgdGhpcyByZXNwb25zZSBpbiBzb21lIHdheT8gRm9yIHNvbWUgdW5rbm93biByZWFzb24gd2UgYWx3YXlzIGdldCBvaz1mYWxzZSBhbmQgc3RhdHVzPTBcblx0XHQvLyBjb25zb2xlLmxvZyhyZXNwb25zZSlcblx0XHQvLyBjb25zb2xlLmxvZyhyZXNwb25zZS5vaylcblx0XHQvLyBjb25zb2xlLmxvZyhyZXNwb25zZS5zdGF0dXMpXG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBQUklWQVRFIE1FVEhPRFNcblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRfc3dpdGNoTWFpblZpZXcodmlld0lkKVxuXHR7XG5cdFx0ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2V4ZC12aWV3c3RhY2snKS5zZWxlY3RlZEVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh2aWV3SWQpO1xuXHR9XG5cblx0X3N3aXRjaFN0YXR1c1ZpZXcodmlld0lkKVxuXHR7XG5cdFx0ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2V4ZC1kZXBsb3lTdGF0dXMnKS5zZWxlY3RlZEVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh2aWV3SWQpO1xuXHR9XG5cblx0X2dldEhlYWx0aFRlbXBsYXRlKGRhdGFJdGVtKVxuXHR7XG5cdFx0bGV0IHN0eWxlID0gJ3RleHQtc3VjY2Vzcyc7XG5cblx0XHRpZiAoIWRhdGFJdGVtWydoZWFsdGgnXSlcblx0XHRcdHN0eWxlID0gJ3RleHQtZGFuZ2VyJztcblxuXHRcdHJldHVybiBgPHNwYW4gY2xhc3M9XCIke3N0eWxlfVwiPjxpIGNsYXNzPVwiZmFzIGZhLWNpcmNsZVwiPjwvaT48L3NwYW4+YDtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFBSSVZBVEUgR0VUVEVSU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7O0EiLCJzb3VyY2VSb290IjoiIn0=