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
@@ -0,0 +1,3383 @@
1
+ /*! (c) gotoAndPlay | All rights reserved */
2
+ (window["webpackJsonpapplication"] = window["webpackJsonpapplication"] || []).push([["module-17"],{
3
+
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;
278
+ }
279
+ return map[req];
280
+ }
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 ^\\.\\/.*$";
287
+
288
+ /***/ }),
289
+
290
+ /***/ "./src/components/charts/chart-utils.js":
291
+ /*!**********************************************!*\
292
+ !*** ./src/components/charts/chart-utils.js ***!
293
+ \**********************************************/
294
+ /*! exports provided: getFormattedDateTime, getBasicSharedTemplate, getMemorySharedTemplate, getMemoryValueAxisLabelTemplate, getNetworkSharedTemplate, getNetworkValueAxisLabelTemplate, getNetworkValueAxisLabelTemplateB, getUserCountSharedTemplate, getTimeRangeTooltipTemplate, getWRBytesLabelTemplate, getBasicTemplate, getMemoryTemplate, getNetworkTemplate */
295
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
296
+
297
+ "use strict";
298
+ __webpack_require__.r(__webpack_exports__);
299
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getFormattedDateTime", function() { return getFormattedDateTime; });
300
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBasicSharedTemplate", function() { return getBasicSharedTemplate; });
301
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getMemorySharedTemplate", function() { return getMemorySharedTemplate; });
302
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getMemoryValueAxisLabelTemplate", function() { return getMemoryValueAxisLabelTemplate; });
303
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNetworkSharedTemplate", function() { return getNetworkSharedTemplate; });
304
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNetworkValueAxisLabelTemplate", function() { return getNetworkValueAxisLabelTemplate; });
305
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNetworkValueAxisLabelTemplateB", function() { return getNetworkValueAxisLabelTemplateB; });
306
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getUserCountSharedTemplate", function() { return getUserCountSharedTemplate; });
307
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getTimeRangeTooltipTemplate", function() { return getTimeRangeTooltipTemplate; });
308
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getWRBytesLabelTemplate", function() { return getWRBytesLabelTemplate; });
309
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBasicTemplate", function() { return getBasicTemplate; });
310
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getMemoryTemplate", function() { return getMemoryTemplate; });
311
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNetworkTemplate", function() { return getNetworkTemplate; });
312
+ /* harmony import */ var _utils_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../utils/utilities */ "./src/utils/utilities.js");
313
+
314
+
315
+ function getFormattedDateTime(date, format = 'dd MMM HH:mm:ss')
316
+ {
317
+ return kendo.toString(date, format);
318
+ }
319
+
320
+ function getBasicSharedTemplate(valueFormat = '{0}') {
321
+ return kendo.template(`
322
+ <div class="chart-tooltip-category"><strong>#: category #</strong></div>
323
+ # for (var i = 0; i < points.length; i++) { #
324
+ <div>
325
+ <i class="fas fa-square" style="color: #: points[i].color # "></i>
326
+ #: points[i].series.name# : #: kendo.format('${valueFormat}', points[i].value) #
327
+ </div>
328
+ # } #
329
+ `);
330
+ }
331
+
332
+ function getMemorySharedTemplate() {
333
+ return function(dataItem) {
334
+ dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
335
+ return kendo.template(`
336
+ <div class="chart-tooltip-category"><strong>#: category #</strong></div>
337
+ # for (var i = 0; i < points.length; i++) { #
338
+ <div>
339
+ <i class="fas fa-square" style="color: #: points[i].color # "></i>
340
+ #: points[i].series.name# : #: bytesToSize(points[i].value) #
341
+ </div>
342
+ # } #
343
+ `)(dataItem);
344
+ };
345
+ }
346
+
347
+ function getMemoryValueAxisLabelTemplate() {
348
+ return function(dataItem) {
349
+ dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
350
+ return kendo.template(`
351
+ #: bytesToSize(value) #
352
+ `)(dataItem);
353
+ };
354
+ }
355
+
356
+ function getNetworkSharedTemplate(categoryFormat = 'dd MMM HH:mm:ss') {
357
+ return function(dataItem) {
358
+ dataItem.kBytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["kBytesToSize"]; // Pass kBytesToSize utility function to template
359
+ return kendo.template(`
360
+ <div class="chart-tooltip-category"><strong>#: kendo.toString(category, '${categoryFormat}') #</strong></div>
361
+ # for (var i = 0; i < points.length; i++) { #
362
+ <div>
363
+ <i class="fas fa-square" style="color: #: points[i].color # "></i>
364
+ #: points[i].series.name# : #: kBytesToSize(points[i].value, 1, '', '/s') #
365
+ </div>
366
+ # } #
367
+ `)(dataItem);
368
+ };
369
+ }
370
+
371
+ function getNetworkValueAxisLabelTemplate() {
372
+ return function(dataItem) {
373
+ dataItem.kBytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["kBytesToSize"]; // Pass kBytesToSize utility function to template
374
+ return kendo.template(`
375
+ #: kBytesToSize(value, 1, '', '/s') #
376
+ `)(dataItem);
377
+ };
378
+ }
379
+
380
+ function getNetworkValueAxisLabelTemplateB() {
381
+ return function(dataItem) {
382
+ dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
383
+ return kendo.template(`
384
+ #: bytesToSize(value, 1, '', '/s') #
385
+ `)(dataItem);
386
+ };
387
+ }
388
+
389
+ function getUserCountSharedTemplate(categoryFormat = 'dd MMM HH:mm:ss') {
390
+ return function(dataItem) {
391
+ return kendo.template(`
392
+ <div class="chart-tooltip-category"><strong>#: kendo.toString(category, '${categoryFormat}') #</strong></div>
393
+ # for (var i = 0; i < points.length; i++) { #
394
+ <div>
395
+ <i class="fas fa-square" style="color: #: points[i].color # "></i>
396
+ #: points[i].series.name# : #: points[i].value #
397
+ </div>
398
+ # } #
399
+ `)(dataItem);
400
+ };
401
+ }
402
+
403
+ function getTimeRangeTooltipTemplate() {
404
+ return function(dataItem) {
405
+ dataItem.getTooltipString = function(v1, v2) {
406
+ if (v1 == v2)
407
+ {
408
+ if (v2 == -24)
409
+ v2 = -23;
410
+
411
+ v1 = v2 - 1;
412
+ }
413
+
414
+ let start = Math.abs(v1);
415
+ let end = Math.abs(v2);
416
+
417
+ return `From ${start} hour${start != 1 ? 's' : ''} ago to ${end > 0 ? ('to ' + end + ' hour' + (end != 1 ? 's' : '') + ' ago') : 'now'}`;
418
+ }; // Pass utility function to template
419
+ return kendo.template(`
420
+ #: getTooltipString(selectionStart, selectionEnd) #
421
+ `)(dataItem);
422
+ };
423
+ }
424
+
425
+ function getWRBytesLabelTemplate() {
426
+ return function(dataItem) {
427
+ return kendo.template(`
428
+ #: value # #: dataItem.unit #
429
+ `)(dataItem);
430
+ };
431
+ }
432
+
433
+ function getBasicTemplate(valueFormat = '{0}') {
434
+ return kendo.template(`
435
+ <div>
436
+ <span class="text-nowrap">#: kendo.toString(new Date(value.x), "dd/MM/yy HH:mm") #</span>
437
+ <br>
438
+ <strong class="text-nowrap">#: series.name #: #: kendo.format('${valueFormat}', value.y) # </strong>
439
+ </div>
440
+ `);
441
+ }
442
+
443
+ function getMemoryTemplate() {
444
+ return function(dataItem) {
445
+ dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
446
+ return kendo.template(`
447
+ <div>
448
+ <span class="text-nowrap">#: kendo.toString(new Date(value.x), "dd/MM/yy HH:mm") #</span>
449
+ <br>
450
+ <strong class="text-nowrap">#: series.name #: #: bytesToSize(value.y) # </strong>
451
+ </div>
452
+ `)(dataItem);
453
+ };
454
+ }
455
+
456
+ function getNetworkTemplate() {
457
+ return function(dataItem) {
458
+ dataItem.bytesToSize = _utils_utilities__WEBPACK_IMPORTED_MODULE_0__["bytesToSize"]; // Pass bytesToSize utility function to template
459
+ return kendo.template(`
460
+ <div>
461
+ <span class="text-nowrap">#: kendo.toString(new Date(value.x), "dd/MM/yy HH:mm") #</span>
462
+ <br>
463
+ <strong class="text-nowrap">#: series.name #: #: bytesToSize(value.y, 1, '', '/s') # </strong>
464
+ </div>
465
+ `)(dataItem);
466
+ };
467
+ }
468
+
469
+
470
+ /***/ }),
471
+
472
+ /***/ "./src/components/charts/user-count-chart.js":
473
+ /*!***************************************************!*\
474
+ !*** ./src/components/charts/user-count-chart.js ***!
475
+ \***************************************************/
476
+ /*! exports provided: UserCountChart */
477
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
478
+
479
+ "use strict";
480
+ __webpack_require__.r(__webpack_exports__);
481
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UserCountChart", function() { return UserCountChart; });
482
+ /* harmony import */ var _chart_utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./chart-utils */ "./src/components/charts/chart-utils.js");
483
+ /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! moment */ "./node_modules/moment/moment.js");
484
+ /* harmony import */ var moment__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(moment__WEBPACK_IMPORTED_MODULE_1__);
485
+
486
+
487
+
488
+ class UserCountChart extends HTMLElement
489
+ {
490
+ constructor()
491
+ {
492
+ super();
493
+
494
+ // Create chart html
495
+ let chartHtml = $('<div>');
496
+ $(this).append(chartHtml);
497
+
498
+ // Initialize chart
499
+ this._chartWidget = this._initChartWidget(chartHtml);
500
+ }
501
+
502
+ _initChartWidget(chartHtml)
503
+ {
504
+ return chartHtml.kendoChart({
505
+ transitions: false,
506
+ chartArea: {
507
+ height: 270,
508
+ background: 'transparent'
509
+ },
510
+ legend: {
511
+ visible: false
512
+ },
513
+ seriesDefaults: {
514
+ type: 'area',
515
+ labels: {
516
+ visible: false,
517
+ format: '{0}',
518
+ background: 'transparent'
519
+ },
520
+ },
521
+ series: [{
522
+ name: 'Users',
523
+ field: 'users',
524
+ categoryField: 'time',
525
+ color: '#fd7d24',
526
+ line: {
527
+ width: 2
528
+ }
529
+ }],
530
+ valueAxis: {
531
+ labels: {
532
+ format: '{0}',
533
+ },
534
+ line: {
535
+ visible: false
536
+ },
537
+ min: 0,
538
+ },
539
+ categoryAxis: {
540
+ majorGridLines: {
541
+ visible: true,
542
+ step: 60
543
+ },
544
+ majorTicks: {
545
+ visible: true,
546
+ step: 60
547
+ },
548
+ labels: {
549
+ visible: true,
550
+ step: 60
551
+ },
552
+ baseUnit: 'minutes',
553
+ type: 'date',
554
+ },
555
+ tooltip: {
556
+ shared: true,
557
+ visible: true,
558
+ sharedTemplate: Object(_chart_utils__WEBPACK_IMPORTED_MODULE_0__["getUserCountSharedTemplate"])('dd MMM HH:mm'),
559
+ background: '#e4e4e4'
560
+ }
561
+ }).data('kendoChart');
562
+ }
563
+
564
+ redraw()
565
+ {
566
+ this._chartWidget.redraw();
567
+ }
568
+
569
+ set range(values)
570
+ {
571
+ this._range = values;
572
+
573
+ this._updateXAxisLimits();
574
+ }
575
+
576
+ get range()
577
+ {
578
+ return this._range;
579
+ }
580
+
581
+ addHistoryEntries(userCountData, samplingRateSeconds)
582
+ {
583
+ let date = new Date();
584
+ let start = moment__WEBPACK_IMPORTED_MODULE_1__(date);
585
+ start.subtract((samplingRateSeconds * userCountData.length), 's')
586
+
587
+ let dataSource = new kendo.data.DataSource();
588
+
589
+ for (let i = 1; i < userCountData.length; i++)
590
+ {
591
+ let date = start.clone();
592
+ date.add(i * samplingRateSeconds, 's');
593
+
594
+ this.addEntry(userCountData[i], dataSource, date.toDate(), false);
595
+ }
596
+
597
+ // Assign datasource to chart
598
+ this._chartWidget.setDataSource(dataSource);
599
+
600
+ // Update axis
601
+ this._updateXAxisLimits();
602
+ }
603
+
604
+ addEntry(userCount, dataSource = null, date = null, updateAxis = true)
605
+ {
606
+ if (date == null)
607
+ date = new Date();
608
+
609
+ let newEntry = {
610
+ time: date,
611
+ users: userCount
612
+ };
613
+
614
+ // Add entry to data source
615
+ if (dataSource == null)
616
+ dataSource = this._dataSource;
617
+
618
+ dataSource.add(newEntry);
619
+
620
+ if (updateAxis)
621
+ this._updateXAxisLimits();
622
+ }
623
+
624
+ _updateXAxisLimits()
625
+ {
626
+ let ds = this._dataSource;
627
+
628
+ if (ds.total() > 0)
629
+ {
630
+ const chartMinimum = moment__WEBPACK_IMPORTED_MODULE_1__(this._lastDate).add(this._range[0], 'h');
631
+ const chartMaximum = moment__WEBPACK_IMPORTED_MODULE_1__(this._lastDate).add(this._range[1], 'h');
632
+
633
+ this._chartWidget.options.categoryAxis.min = chartMinimum.toDate();
634
+ this._chartWidget.options.categoryAxis.max = chartMaximum.toDate();
635
+
636
+ this._chartWidget.redraw();
637
+ }
638
+ }
639
+
640
+ get _dataSource()
641
+ {
642
+ return this._chartWidget.dataSource;
643
+ }
644
+ }
645
+
646
+ // DEFINE COMPONENT
647
+ if (!window.customElements.get('user-count-chart'))
648
+ window.customElements.define('user-count-chart', UserCountChart);
649
+
650
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
651
+
652
+ /***/ }),
653
+
654
+ /***/ "./src/components/module-specific/match-expression-builder.js":
655
+ /*!********************************************************************!*\
656
+ !*** ./src/components/module-specific/match-expression-builder.js ***!
657
+ \********************************************************************/
658
+ /*! exports provided: MatchExpressionBuilder */
659
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
660
+
661
+ "use strict";
662
+ __webpack_require__.r(__webpack_exports__);
663
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MatchExpressionBuilder", function() { return MatchExpressionBuilder; });
664
+ class MatchExpressionBuilder extends HTMLElement
665
+ {
666
+ constructor()
667
+ {
668
+ super();
669
+
670
+ this.EXPRESSION_UPDATED_EVENT = 'expressionUpdated';
671
+
672
+ this._dialog = $(`
673
+ <div class="modal" id="matchExprBuilderModal" tabindex="-1" role="dialog" aria-labelledby="matchExprBuilderModalTitle" aria-hidden="true">
674
+ <div class="modal-dialog modal-dialog-centered modal-lg" role="document">
675
+ <div class="modal-content">
676
+ <div class="modal-header">
677
+ <h5 class="modal-title text-primary" id="matchExprBuilderModalTitle">...</h5>
678
+ </div>
679
+ <div class="modal-body p-0">
680
+ <form class="bg-color-default p-3">
681
+ <div class="d-inline-flex align-items-center radio-button-group inline-form-groups">
682
+ <div class="custom-control custom-radio custom-control-inline mr-2">
683
+ <input type="radio" id="andOperatorRB" name="operatorRBG" class="custom-control-input" value="AND" checked disabled>
684
+ <label class="custom-control-label" for="andOperatorRB">AND</label>
685
+ </div>
686
+ <div class="custom-control custom-radio custom-control-inline mr-2">
687
+ <input type="radio" id="orOperatorRB" name="operatorRBG" class="custom-control-input" value="OR" disabled>
688
+ <label class="custom-control-label" for="orOperatorRB">OR</label>
689
+ </div>
690
+ </div>
691
+ <div class="d-inline-block">
692
+ <div class="inline-form-groups my-1">
693
+ <input id="varNameCB"/>
694
+ </div>
695
+ <div class="inline-form-groups my-1">
696
+ <input id="typeDD" class="matchTypeDropdown"/>
697
+ <input id="conditionDD" class="matchConditionDropdown"/>
698
+ </div>
699
+ </div>
700
+ <div class="d-inline inline-form-groups">
701
+ <input id="valueIn" class="k-textbox mt-1" placeholder="Value"/>
702
+ <button id="matchExprAddBt" type="button" class="k-button k-secondary mt-1"><i class="fas fa-plus mr-1"></i>Add</button>
703
+ </div>
704
+ </form>
705
+
706
+ <div id="matchExprGrid" class="m-3"></div>
707
+ </div>
708
+ <div class="modal-footer d-flex">
709
+ <div class="flex-grow-1 text-left">
710
+ <button id="matchExprApplyBt" type="button" class="k-button k-primary mr-2"><i class="fas fa-check-circle mr-1"></i>Apply</button>
711
+ </div>
712
+ <div class="flex-grow-1 text-right">
713
+ <button id="matchExprRemoveBt" type="button" class="k-button k-secondary" disabled><i class="fas fa-minus-circle mr-1"></i>Remove selected</button>
714
+ <button id="matchExprClearBt" type="button" class="k-button k-secondary"><i class="fas fa-times-circle mr-1"></i>Clear all</button>
715
+ </div>
716
+ </div>
717
+ </div>
718
+ </div>
719
+ </div>
720
+ `);
721
+
722
+ $('#matchExprAddBt', this._dialog).on('click', $.proxy(this._onAddBtClick, this));
723
+ $('#matchExprApplyBt', this._dialog).on('click', $.proxy(this._onApplyBtClick, this));
724
+ $('#matchExprRemoveBt', this._dialog).on('click', $.proxy(this._onRemoveBtClick, this));
725
+ $('#matchExprClearBt', this._dialog).on('click', $.proxy(this._onClearBtClick, this));
726
+
727
+ // INITIALIZE FORM ITEMS
728
+
729
+ this._varNameCb = $('#varNameCB', this._dialog).kendoComboBox({
730
+ dataTextField: 'label',
731
+ dataValueField: 'value',
732
+ placeholder: 'Variable name',
733
+ }).data('kendoComboBox');
734
+
735
+ // Set types dropdown data source
736
+ // NOTE: in order to avoid XxxMatch objects to be wrapped by Kendo data source, we have to pass them using _ property names
737
+ let typeDS = [];
738
+
739
+ // Boolean ----------------
740
+ typeDS.push({
741
+ label: 'Boolean',
742
+ _value: SFS2X.BoolMatch.EQUALS,
743
+ conditions: [
744
+ {
745
+ label: SFS2X.BoolMatch.EQUALS.symbol,
746
+ _value: SFS2X.BoolMatch.EQUALS,
747
+ },
748
+ {
749
+ label: SFS2X.BoolMatch.NOT_EQUALS.symbol,
750
+ _value: SFS2X.BoolMatch.NOT_EQUALS,
751
+ }
752
+ ]
753
+ });
754
+
755
+ // Number ----------------
756
+ typeDS.push({
757
+ label: 'Number',
758
+ _value: SFS2X.NumberMatch.EQUALS,
759
+ conditions: [
760
+ {
761
+ label: SFS2X.NumberMatch.EQUALS.symbol,
762
+ _value: SFS2X.NumberMatch.EQUALS,
763
+ },
764
+ {
765
+ label: SFS2X.NumberMatch.NOT_EQUALS.symbol,
766
+ _value: SFS2X.NumberMatch.NOT_EQUALS,
767
+ },
768
+ {
769
+ label: SFS2X.NumberMatch.GREATER_THAN.symbol,
770
+ _value: SFS2X.NumberMatch.GREATER_THAN,
771
+ },
772
+ {
773
+ label: SFS2X.NumberMatch.LESS_THAN.symbol,
774
+ _value: SFS2X.NumberMatch.LESS_THAN,
775
+ },
776
+ {
777
+ label: SFS2X.NumberMatch.GREATER_THAN_OR_EQUAL_TO.symbol,
778
+ _value: SFS2X.NumberMatch.GREATER_THAN_OR_EQUAL_TO,
779
+ },
780
+ {
781
+ label: SFS2X.NumberMatch.LESS_THAN_OR_EQUAL_TO.symbol,
782
+ _value: SFS2X.NumberMatch.LESS_THAN_OR_EQUAL_TO,
783
+ }
784
+ ]
785
+ });
786
+
787
+ // String ----------------
788
+ typeDS.push({
789
+ label: 'String',
790
+ _value: SFS2X.StringMatch.EQUALS,
791
+ conditions: [
792
+ {
793
+ label: SFS2X.StringMatch.EQUALS.symbol,
794
+ _value: SFS2X.StringMatch.EQUALS,
795
+ },
796
+ {
797
+ label: SFS2X.StringMatch.NOT_EQUALS.symbol,
798
+ _value: SFS2X.StringMatch.NOT_EQUALS,
799
+ },
800
+ {
801
+ label: SFS2X.StringMatch.CONTAINS.symbol,
802
+ _value: SFS2X.StringMatch.CONTAINS,
803
+ },
804
+ {
805
+ label: SFS2X.StringMatch.STARTS_WITH.symbol,
806
+ _value: SFS2X.StringMatch.STARTS_WITH,
807
+ },
808
+ {
809
+ label: SFS2X.StringMatch.ENDS_WITH.symbol,
810
+ _value: SFS2X.StringMatch.ENDS_WITH,
811
+ }
812
+ ]
813
+ });
814
+
815
+ this._typeDd = $('#typeDD', this._dialog).kendoDropDownList({
816
+ dataSource: typeDS,
817
+ dataTextField: 'label',
818
+ dataValueField: '_value',
819
+ optionLabel: {
820
+ label: 'Type',
821
+ _value: ''
822
+ },
823
+ optionLabelTemplate: '<span class="text-muted">#:label#</span>',
824
+ change: $.proxy(function() {
825
+ if (this._typeDd && this._typeDd.select())
826
+ {
827
+ let selectedType = this._typeDd.dataItem(this._typeDd.select());
828
+ this._conditionDd.setDataSource(selectedType.conditions);
829
+ this._conditionDd.select(1);
830
+ }
831
+ }, this)
832
+ }).data('kendoDropDownList');
833
+
834
+ this._conditionDd = $('#conditionDD', this._dialog).kendoDropDownList({
835
+ dataTextField: 'label',
836
+ dataValueField: '_value',
837
+ optionLabel: {
838
+ label: 'Condition',
839
+ _value: ''
840
+ },
841
+ optionLabelTemplate: '<span class="text-muted">#:label#</span>',
842
+ }).data('kendoDropDownList');
843
+
844
+ this._valueIn = $('#valueIn', this._dialog);
845
+
846
+ // INITIALIZE GRID
847
+
848
+ this._grid = $('#matchExprGrid', this._dialog).kendoGrid({
849
+ dataSource: [],
850
+ resizable: true,
851
+ selectable: 'row',
852
+ change: $.proxy(this._onGridSelectionChange, this),
853
+ noRecords: {
854
+ template: 'No entries.'
855
+ },
856
+ columns: [
857
+ {
858
+ field: 'operator',
859
+ title: 'Operator',
860
+ width: 90
861
+ },
862
+ {
863
+ field: 'label',
864
+ title: 'Name',
865
+ width: 120
866
+ },
867
+ {
868
+ field: 'typeLabel',
869
+ title: 'Type',
870
+ width: 85
871
+ },
872
+ {
873
+ field: 'symbol',
874
+ title: 'Condition',
875
+ width: 95
876
+ },
877
+ {
878
+ field: 'value',
879
+ title: 'Value',
880
+ width: 200
881
+ },
882
+ ]
883
+ }).data('kendoGrid');
884
+ }
885
+
886
+ get title()
887
+ {
888
+ return $('#matchExprBuilderModalTitle', this._dialog).text();
889
+ }
890
+
891
+ set title(value)
892
+ {
893
+ $('#matchExprBuilderModalTitle', this._dialog).text(value);
894
+ }
895
+
896
+ get predefinedVarNames()
897
+ {
898
+ return this._predefinedVarNames;
899
+ }
900
+
901
+ set predefinedVarNames(value)
902
+ {
903
+ this._predefinedVarNames = value;
904
+
905
+ this._varNameCb.setDataSource(value);
906
+ }
907
+
908
+ get filterExpression()
909
+ {
910
+ return this._filterExpression;
911
+ }
912
+
913
+ show()
914
+ {
915
+ this._dialog.modal({
916
+ backdrop: 'static',
917
+ keyboard: false,
918
+ show: true
919
+ });
920
+ }
921
+
922
+ _onGridSelectionChange()
923
+ {
924
+ let selectedRows = this._grid.select();
925
+ let selectedDataItems = [];
926
+
927
+ for (let i = 0; i < selectedRows.length; i++)
928
+ {
929
+ let dataItem = this._grid.dataItem(selectedRows[i]);
930
+ selectedDataItems.push(dataItem);
931
+ }
932
+
933
+ // Enable/disable remove button
934
+ $('#matchExprRemoveBt', this._dialog).attr('disabled', selectedDataItems.length == 0);
935
+ }
936
+
937
+ _onAddBtClick()
938
+ {
939
+ if (this._varNameCb.value() != '' && this._typeDd.select())
940
+ {
941
+ // Variable name and label
942
+ let varName, varLabel;
943
+
944
+ if (this._varNameCb.select() > -1)
945
+ {
946
+ let dataItem = this._varNameCb.dataItem(this._varNameCb.select());
947
+ varName = dataItem.value;
948
+ varLabel = dataItem.label;
949
+ }
950
+ else
951
+ varName = varLabel = this._varNameCb.value();
952
+
953
+ // Variable type's label
954
+ let typeLabel = this._typeDd.dataItem(this._typeDd.select()).label;
955
+
956
+ // Match condition
957
+ let condition = this._conditionDd.dataItem(this._conditionDd.select())._value;
958
+
959
+ // Expression operator
960
+ let operator = this._grid.dataSource.total() > 0 ? $('input[name=operatorRBG]:checked', this._dialog).val() : null;
961
+
962
+ // Variable value
963
+ let val = this._valueIn.val();
964
+ let varValue;
965
+
966
+ if (condition instanceof SFS2X.BoolMatch)
967
+ varValue = (val == 'true' ? true : false);
968
+ else if (condition instanceof SFS2X.NumberMatch)
969
+ varValue = (isNaN(Number(val)) ? 0 : Number(val));
970
+ else
971
+ varValue = val;
972
+
973
+ // Add item to grid
974
+ let exprPart = this._getExpressionPart(varLabel, varName, varValue, typeLabel, condition, operator);
975
+ this._grid.dataSource.add(exprPart);
976
+
977
+ // Reset inputs
978
+ this._varNameCb.value('');
979
+ this._valueIn.val('');
980
+
981
+ // Enable operator radio buttons
982
+ this._enableOperatorRb(true);
983
+ }
984
+ }
985
+
986
+ _onApplyBtClick()
987
+ {
988
+ // Hide dialog
989
+ this._dialog.modal('hide');
990
+
991
+ // Clear grid selection
992
+ this._grid.clearSelection();
993
+
994
+ // Build final match expression
995
+ this._filterExpression = null;
996
+
997
+ if (this._grid.dataSource.total() > 0)
998
+ {
999
+ let expPart = this._grid.dataSource.at(0);
1000
+ this._filterExpression = new SFS2X.MatchExpression(expPart.name, expPart._condition, expPart.value);
1001
+
1002
+ for (let i = 1; i < this._grid.dataSource.total(); i++)
1003
+ {
1004
+ expPart = this._grid.dataSource.at(i);
1005
+
1006
+ if (expPart.operator == SFS2X.LogicOperator.AND.id)
1007
+ this._filterExpression = this._filterExpression.and(expPart.name, expPart._condition, expPart.value);
1008
+ else if (expPart.operator == SFS2X.LogicOperator.OR.id)
1009
+ this._filterExpression = this._filterExpression.or(expPart.name, expPart._condition, expPart.value);
1010
+ }
1011
+ }
1012
+
1013
+ // Fire event
1014
+ let evt = new CustomEvent(this.EXPRESSION_UPDATED_EVENT, {
1015
+ detail: null,
1016
+ bubbles: false,
1017
+ cancelable: false
1018
+ });
1019
+
1020
+ this.dispatchEvent(evt);
1021
+ }
1022
+
1023
+ _onRemoveBtClick()
1024
+ {
1025
+ let dataItem = this._grid.dataItem(this._grid.select());
1026
+ this._grid.dataSource.remove(dataItem);
1027
+
1028
+ // Clear grid selection
1029
+ this._grid.clearSelection();
1030
+
1031
+ if (this._grid.dataSource.total() == 0)
1032
+ {
1033
+ // Disable operator radio buttons
1034
+ this._enableOperatorRb(false);
1035
+ }
1036
+ else
1037
+ {
1038
+ // Reset operator on first entry
1039
+ this._grid.dataSource.at(0).operator = null;
1040
+ this._grid.refresh();
1041
+ }
1042
+ }
1043
+
1044
+ _onClearBtClick()
1045
+ {
1046
+ // Reset form
1047
+ $('#andOperatorRB', this._dialog).attr('checked', true);
1048
+ $('#orOperatorRB', this._dialog).attr('checked', false);
1049
+ this._enableOperatorRb(false);
1050
+
1051
+ this._varNameCb.value('');
1052
+ this._typeDd.select(0);
1053
+ this._conditionDd.select(0);
1054
+
1055
+ this._valueIn.val('');
1056
+
1057
+ // Clear grid selection
1058
+ this._grid.clearSelection();
1059
+
1060
+ // Clear table
1061
+ this._grid.setDataSource([]);
1062
+ }
1063
+
1064
+ _getExpressionPart(varLabel, varName, varValue, typeLabel, condition, operator)
1065
+ {
1066
+ return {
1067
+ 'label': varLabel,
1068
+ 'name': varName,
1069
+ 'value': varValue,
1070
+ 'typeLabel': typeLabel,
1071
+ 'symbol': condition.symbol,
1072
+ 'operator': operator,
1073
+ '_condition': condition,
1074
+ };
1075
+ }
1076
+
1077
+ _enableOperatorRb(enable)
1078
+ {
1079
+ $('#andOperatorRB', this._dialog).attr('disabled', !enable);
1080
+ $('#orOperatorRB', this._dialog).attr('disabled', !enable);
1081
+ }
1082
+ }
1083
+
1084
+ // DEFINE COMPONENT
1085
+ if (!window.customElements.get('match-expression-builder'))
1086
+ window.customElements.define('match-expression-builder', MatchExpressionBuilder);
1087
+
1088
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1089
+
1090
+ /***/ }),
1091
+
1092
+ /***/ "./src/components/sidebar-layout.js":
1093
+ /*!******************************************!*\
1094
+ !*** ./src/components/sidebar-layout.js ***!
1095
+ \******************************************/
1096
+ /*! exports provided: SidebarLayout */
1097
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1098
+
1099
+ "use strict";
1100
+ __webpack_require__.r(__webpack_exports__);
1101
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SidebarLayout", function() { return SidebarLayout; });
1102
+ class SidebarLayout extends HTMLElement
1103
+ {
1104
+ constructor()
1105
+ {
1106
+ super();
1107
+
1108
+ // Attach a shadow root
1109
+ const shadowRoot = this.attachShadow({mode: 'open'});
1110
+ shadowRoot.innerHTML = `
1111
+ <style>
1112
+ :host {
1113
+ display: flex;
1114
+ flex-direction: row;
1115
+ }
1116
+
1117
+ @media (max-width: 575.98px) {
1118
+ :host(.split-xs) ::slotted(:not([aria-selected="true"])) {
1119
+ display: none !important;
1120
+ }
1121
+
1122
+ :host(.split-xs) ::slotted([aria-selected="true"]) {
1123
+ flex-grow: 1;
1124
+ }
1125
+ }
1126
+
1127
+ @media (max-width: 767.98px) {
1128
+ :host(.split-sm) ::slotted(:not([aria-selected="true"])) {
1129
+ display: none !important;
1130
+ }
1131
+
1132
+ :host(.split-sm) ::slotted([aria-selected="true"]) {
1133
+ flex-grow: 1;
1134
+ }
1135
+ }
1136
+
1137
+ @media (max-width: 991.98px) {
1138
+ :host(.split-md) ::slotted(:not([aria-selected="true"])) {
1139
+ display: none !important;
1140
+ }
1141
+
1142
+ :host(.split-md) ::slotted([aria-selected="true"]) {
1143
+ flex-grow: 1;
1144
+ }
1145
+ }
1146
+
1147
+ @media (max-width: 1199.98px) {
1148
+ :host(.split-lg) ::slotted(:not([aria-selected="true"])) {
1149
+ display: none !important;
1150
+ }
1151
+
1152
+ :host(.split-lg) ::slotted([aria-selected="true"]) {
1153
+ flex-grow: 1;
1154
+ }
1155
+ }
1156
+
1157
+ .side-col::slotted(*) {
1158
+ }
1159
+
1160
+ .main-col::slotted(*) {
1161
+ flex-grow: 1;
1162
+ }
1163
+ </style>
1164
+
1165
+ <slot class="side-col" name="side-column"></slot>
1166
+ <slot class="main-col" name="main-column"></slot>
1167
+ `;
1168
+
1169
+ // Set initial selection
1170
+ this.selectedIndex = 0;
1171
+ }
1172
+
1173
+ get selectedPanel()
1174
+ {
1175
+ return this._selectedPanel;
1176
+ }
1177
+
1178
+ set selectedPanel(element) // 'side' or 'main'
1179
+ {
1180
+ if (element != null && element.parentNode == this)
1181
+ {
1182
+ this._selectedPanel = element;
1183
+
1184
+ for (let element of this.children)
1185
+ {
1186
+ if (element == this._selectedPanel)
1187
+ element.setAttribute('aria-selected', 'true');
1188
+ else
1189
+ element.removeAttribute('aria-selected');
1190
+ }
1191
+ }
1192
+ else
1193
+ {
1194
+ console.error('Element is not a child of SidebarLayout');
1195
+ }
1196
+ }
1197
+
1198
+ get selectedIndex()
1199
+ {
1200
+ return Array.from(this.children).indexOf(this._selectedPanel);
1201
+ }
1202
+
1203
+ set selectedIndex(index)
1204
+ {
1205
+ if (this.children.length > 0)
1206
+ {
1207
+ if (this.children[index] == null)
1208
+ {
1209
+ console.error('Invalid SidebarLayout index');
1210
+ return;
1211
+ }
1212
+
1213
+ let element = this.children[index];
1214
+ this.selectedPanel = element;
1215
+ }
1216
+ }
1217
+ }
1218
+
1219
+ // DEFINE COMPONENT
1220
+ if (!window.customElements.get('sidebar-layout'))
1221
+ window.customElements.define('sidebar-layout', SidebarLayout);
1222
+
1223
+
1224
+ /***/ }),
1225
+
1226
+ /***/ "./src/modules/zone-monitor.js":
1227
+ /*!*************************************!*\
1228
+ !*** ./src/modules/zone-monitor.js ***!
1229
+ \*************************************/
1230
+ /*! exports provided: default */
1231
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1232
+
1233
+ "use strict";
1234
+ __webpack_require__.r(__webpack_exports__);
1235
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return ZoneMonitor; });
1236
+ /* harmony import */ var _base_module__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./base-module */ "./src/modules/base-module.js");
1237
+ /* harmony import */ var _components_sidebar_layout__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components/sidebar-layout */ "./src/components/sidebar-layout.js");
1238
+ /* harmony import */ var _components_module_specific_match_expression_builder__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../components/module-specific/match-expression-builder */ "./src/components/module-specific/match-expression-builder.js");
1239
+ /* harmony import */ var _utils_uibuilder_config_interface_builder__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils/uibuilder/config-interface-builder */ "./src/utils/uibuilder/config-interface-builder.js");
1240
+ /* harmony import */ var _utils_utilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utils/utilities */ "./src/utils/utilities.js");
1241
+ /* harmony import */ var _utils_match_properties__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../utils/match-properties */ "./src/utils/match-properties.js");
1242
+ /* harmony import */ var _components_charts_user_count_chart__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../components/charts/user-count-chart */ "./src/components/charts/user-count-chart.js");
1243
+ /* harmony import */ var _components_charts_chart_utils__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../components/charts/chart-utils */ "./src/components/charts/chart-utils.js");
1244
+
1245
+
1246
+
1247
+
1248
+
1249
+
1250
+
1251
+
1252
+
1253
+ class ZoneMonitor extends _base_module__WEBPACK_IMPORTED_MODULE_0__["BaseModule"]
1254
+ {
1255
+ constructor()
1256
+ {
1257
+ super('zoneMonitor');
1258
+
1259
+ this.MONITORED_TYPE_ZONE = 'zone';
1260
+ this.MONITORED_TYPE_ROOM = 'room';
1261
+ this.MONITORED_TYPE_USER = 'user';
1262
+
1263
+ this.ANY_LABEL = '[any]';
1264
+ this.DEFAULT_GROUP_NAME = 'default';
1265
+ this.MAX_EXTENSION_LOG_SIZE = 300;
1266
+ this.KICK_BAN_DEFAULT_DELAY = 5;
1267
+
1268
+ // Outgoing requests
1269
+ this.REQ_GET_DATA = 'getData';
1270
+ this.REQ_SET_ZONE_SETTINGS = 'setZoneSettings';
1271
+ this.REQ_SET_ROOM_SETTINGS = 'setRoomSettings';
1272
+ this.REQ_SET_USER_SETTINGS = 'setUserSettings';
1273
+ this.REQ_RELOAD_ZONE_EXT = 'reloadZoneExt';
1274
+ this.REQ_RELOAD_WORDS = 'reloadWords';
1275
+ this.REQ_DISCONNECT_USER = 'disconnUser';
1276
+ this.REQ_KICK_USER = 'kickUser';
1277
+ this.REQ_BAN_USER = 'banUser';
1278
+ this.REQ_GET_ROOM_CONFIG = 'getRoomConfig';
1279
+ this.REQ_CREATE_ROOM = 'createRoom';
1280
+ this.REQ_REMOVE_ROOM = 'removeRoom';
1281
+ this.REQ_ADMIN_MSG = 'adminMsg';
1282
+
1283
+ // Incoming responses
1284
+ this.RESP_DATA = 'data';
1285
+ this.RESP_UNEXPECTED_ERROR = 'unexpError';
1286
+ this.RESP_UPDATE_ERROR = 'updateError';
1287
+ this.RESP_ROOM_CONFIG = 'roomConfig';
1288
+ this.RESP_ROOM_CONFIG_ERROR = 'roomConfigErr';
1289
+ this.RESP_ROOM_CREATED = 'roomCreated';
1290
+ this.RESP_ROOM_CREATION_ERROR = 'roomError';
1291
+ this.RESP_LOG_MESSAGES = 'log'; // This response doesn't have a corresponding request because it is managed by a server event listener
1292
+
1293
+ this._currentRequestId = -1;
1294
+ }
1295
+
1296
+ //------------------------------------
1297
+ // COMMON MODULE INTERFACE METHODS
1298
+ // This members are used by the main controller
1299
+ // to communicate with the module's controller.
1300
+ //------------------------------------
1301
+
1302
+ initialize(idData, shellController)
1303
+ {
1304
+ // Call super method
1305
+ super.initialize(idData, shellController);
1306
+
1307
+ // Set monitoring interface
1308
+ this._setMonitoringInterface();
1309
+
1310
+ // Initialize progress bar
1311
+ $('#znm-progressBar').kendoProgressBar({
1312
+ min: 0,
1313
+ max: 100,
1314
+ value: false,
1315
+ type: 'value',
1316
+ animation: {
1317
+ duration: 400
1318
+ }
1319
+ });
1320
+
1321
+ // LISTS
1322
+
1323
+ // Initialize interval dropdown
1324
+ this._intervalDropDown = $('#znm-intervalDD').kendoDropDownList({
1325
+ valueTemplate: '<span class="text-muted pr-1">Interval:</span><span>#:data.text#</span>',
1326
+ change: $.proxy(this._onUpdateIntervalChange, this)
1327
+ }).data('kendoDropDownList');
1328
+
1329
+ // Initialize pane bar
1330
+ this._accordion = $('#znm-panelbar').kendoPanelBar({
1331
+ expandMode: 'single',
1332
+ change: $.proxy(this._onEntitiesPanelChange, this)
1333
+ }).data('kendoPanelBar');
1334
+
1335
+ // Initialize lists
1336
+ this._zoneListBox = $("#znm-zoneList").kendoListBox({
1337
+ template: '<div>#:data.name# (#:data.users#)</div>',
1338
+ change: $.proxy(this._onZoneSelected, this)
1339
+ }).data('kendoListBox');
1340
+
1341
+ this._zoneListBox.wrapper.find('.k-list').on('dblclick', '.k-item', $.proxy(this._onMonitorSelectionBtClick, this));
1342
+
1343
+ this._roomListBox = $("#znm-roomList").kendoListBox({
1344
+ template: '<div>#:data.name# (#:data.users#)</div>',
1345
+ change: $.proxy(this._onRoomSelected, this)
1346
+ }).data('kendoListBox');
1347
+
1348
+ this._roomListBox.wrapper.find('.k-list').on('dblclick', '.k-item', $.proxy(this._onMonitorSelectionBtClick, this));
1349
+
1350
+ this._userListBox = $("#znm-userList").kendoListBox({
1351
+ template: '<div>#:data.name#</div>',
1352
+ change: $.proxy(this._onUserSelected, this)
1353
+ }).data('kendoListBox');
1354
+
1355
+ this._userListBox.wrapper.find('.k-list').on('dblclick', '.k-item', $.proxy(this._onMonitorSelectionBtClick, this));
1356
+
1357
+ // Initialize Room Groups dropdown
1358
+ this._groupsDropDown = $('#znm-roomGroupsDD').kendoDropDownList({
1359
+ dataTextField: 'label',
1360
+ dataValueField: 'name',
1361
+ change: $.proxy(this._onGroupChange, this)
1362
+ }).data('kendoDropDownList');
1363
+
1364
+ // Build initial groups list
1365
+ this._setGroupsDataProvider(null);
1366
+
1367
+ // Create interface builder instances
1368
+ this._interfaceBuilder = new _utils_uibuilder_config_interface_builder__WEBPACK_IMPORTED_MODULE_3__["ConfigInterfaceBuilder"]();
1369
+ this._roomCreationIBuilder = new _utils_uibuilder_config_interface_builder__WEBPACK_IMPORTED_MODULE_3__["ConfigInterfaceBuilder"]();
1370
+
1371
+ // Add listener to show limit warning tooltips
1372
+ $('#znm-panelbar').kendoTooltip({
1373
+ filter: 'i[title].limit-warning',
1374
+ position: 'right',
1375
+ width: '250px',
1376
+ content: function(e) {
1377
+ return `<div class="help-tooltip">${e.target.data('title')}</div>`;
1378
+ }
1379
+ });
1380
+
1381
+ // ROOM CREATION PANEL
1382
+
1383
+ // Add click listener to Create & Remove Room buttons
1384
+ $('#znm-createRoomBt').on('click', $.proxy(this._onCreateRoomBtClick, this));
1385
+ $('#znm-removeRoomBt').on('click', $.proxy(this._onRemoveRoomBtClick, this));
1386
+
1387
+ // Configure room creation panel
1388
+ $('#znm-createRoomModal').modal({
1389
+ backdrop: 'static',
1390
+ keyboard: false,
1391
+ show: false,
1392
+ });
1393
+
1394
+ // Add listener for room creation panel's create button click
1395
+ $('#znm-roomCreatorCreateBt').on('click', $.proxy(this._onRoomCreatorCreateBtClick, this));
1396
+
1397
+ // Add listener for room creation panel hide
1398
+ $('#znm-createRoomModal').on('hidden.bs.modal', $.proxy(this._onCreateRoomModalHidden, this));
1399
+
1400
+ // ROOM & USER FILTERING PANELS
1401
+
1402
+ // Setup match expression builder panel for rooms
1403
+ this._roomFilter = document.getElementById('znm-roomFilter');
1404
+ this._roomFilter.title = 'Room Filter Expression Builder';
1405
+ this._roomFilter.predefinedVarNames = _utils_match_properties__WEBPACK_IMPORTED_MODULE_5__["RoomPropertiesData"].propertiesArray;
1406
+ $(this._roomFilter).on(this._roomFilter.EXPRESSION_UPDATED_EVENT, $.proxy(this._onRoomFilterUpdated, this));
1407
+
1408
+ $('#znm-filterRoomBt').on('click', $.proxy(this._onShowRoomFilterBtClick, this));
1409
+ $('#znm-applyRoomFilterCB').on('change', $.proxy(this._onApplyBtChange, this));
1410
+
1411
+ // Setup match expression builder panel for users
1412
+ this._userFilter = document.getElementById('znm-userFilter');
1413
+ this._userFilter.title = 'User Filter Expression Builder';
1414
+ this._userFilter.predefinedVarNames = _utils_match_properties__WEBPACK_IMPORTED_MODULE_5__["UserPropertiesData"].propertiesArray;
1415
+ $(this._userFilter).on(this._userFilter.EXPRESSION_UPDATED_EVENT, $.proxy(this._onUserFilterUpdated, this));
1416
+
1417
+ $('#znm-filterUserBt').on('click', $.proxy(this._onShowUserFilterBtClick, this));
1418
+ $('#znm-applyUserFilterCB').on('change', $.proxy(this._onApplyBtChange, this));
1419
+
1420
+ // MAIN CONTROLS
1421
+
1422
+ $('#znm-monitorBt').on('click', $.proxy(this._onMonitorSelectionBtClick, this));
1423
+ $('#znm-sendMessageBt').on('click', $.proxy(this._onSendAdminMsgBtClick, this));
1424
+ $('#znm-messageIn').on('keyup', $.proxy(this._onSendAdminMsgInKeyUp, this));
1425
+
1426
+ // MONITORING CONTROLS
1427
+
1428
+ $('#znm-closeMonitorBt').on('click', $.proxy(this._onCloseMonitorBtClick, this));
1429
+ $('#znm-editBt').on('click', $.proxy(this._onEditBtClick, this));
1430
+ $('#znm-cancelBt').on('click', $.proxy(this._onCancelBtClick, this));
1431
+ $('#znm-submitBt').on('click', $.proxy(this._onSubmitBtClick, this));
1432
+
1433
+ // Hide edit controls
1434
+ $('#znm-editControls').hide();
1435
+
1436
+ // ZONE MONITOR ---------------------
1437
+
1438
+ // Set reference to user count chart
1439
+ this._userCountChart = document.getElementById('znm-userCountChart');
1440
+
1441
+ // Initialize time range slider
1442
+ this._timeSlider = $('#znm-timeSlider').kendoRangeSlider({
1443
+ min: -24,
1444
+ max: 0,
1445
+ smallStep: 1,
1446
+ largeStep: 0,
1447
+ change: $.proxy(this._onTimeRangeChange, this),
1448
+ tooltip: {
1449
+ template: Object(_components_charts_chart_utils__WEBPACK_IMPORTED_MODULE_7__["getTimeRangeTooltipTemplate"])()
1450
+ },
1451
+ leftDragHandleTitle: 'Drag',
1452
+ rightDragHandleTitle: 'Drag',
1453
+ }).data('kendoRangeSlider');
1454
+
1455
+ // Reset time range on user count chart
1456
+ this._onTimeRangeChange();
1457
+
1458
+ // Add button click listeners
1459
+ $('#znm-reloadWordsBt').on('click', $.proxy(this._onWordsReloadBtClick, this));
1460
+ $('#znm-reloadZoneExtBt').on('click', $.proxy(this._onZoneExtReloadBtClick, this));
1461
+
1462
+ // Initialize extension log grid
1463
+ this._zoneExtLogGrid = $('#znm-zoneExtLogGrid').kendoGrid({
1464
+ dataSource: [],
1465
+ resizable: true,
1466
+ selectable: false,
1467
+ noRecords: {
1468
+ template: 'No entries.'
1469
+ },
1470
+ columns: [
1471
+ {
1472
+ field: 'timestamp',
1473
+ title: 'Timestamp',
1474
+ width: 180
1475
+ },
1476
+ {
1477
+ field: 'level',
1478
+ title: 'Level',
1479
+ width: 100
1480
+ },
1481
+ {
1482
+ field: 'message',
1483
+ title: 'Message',
1484
+ width: 400
1485
+ },
1486
+ ],
1487
+ dataBound: function() {
1488
+ this.content.scrollTop(this.tbody.height()); // Scroll to bottom
1489
+ }
1490
+ }).data('kendoGrid');
1491
+
1492
+ // ROOM MONITOR ---------------------
1493
+
1494
+ // Initialize extension log grid
1495
+ this._roomExtLogGrid = $('#znm-roomExtLogGrid').kendoGrid({
1496
+ dataSource: [],
1497
+ resizable: true,
1498
+ selectable: false,
1499
+ noRecords: {
1500
+ template: 'No entries.'
1501
+ },
1502
+ columns: [
1503
+ {
1504
+ field: 'timestamp',
1505
+ title: 'Timestamp',
1506
+ width: 180
1507
+ },
1508
+ {
1509
+ field: 'level',
1510
+ title: 'Level',
1511
+ width: 100
1512
+ },
1513
+ {
1514
+ field: 'message',
1515
+ title: 'Message',
1516
+ width: 400
1517
+ },
1518
+ ],
1519
+ dataBound: function() {
1520
+ this.content.scrollTop(this.tbody.height()); // Scroll to bottom
1521
+ }
1522
+ }).data('kendoGrid');
1523
+
1524
+ // USER MONITOR ---------------------
1525
+
1526
+ this._kickDelayIn = $('#znm-kickDelayNS').kendoNumericTextBox({
1527
+ min: 0,
1528
+ step: 1,
1529
+ format: '#',
1530
+ placeholder: 'Delay (s)'
1531
+ }).data('kendoNumericTextBox');
1532
+
1533
+ this._banModeDd = $('#znm-banModeDD').kendoDropDownList({
1534
+ dataSource: ['IP', 'NAME'],
1535
+ autoWidth: true,
1536
+ optionLabel: {
1537
+ text: 'Mode'
1538
+ },
1539
+ optionLabelTemplate: '<span class="text-muted">#:text#</span>',
1540
+ }).data('kendoDropDownList');
1541
+
1542
+ this._banDurUnitDd = $('#znm-banDurationUnitDD').kendoDropDownList({
1543
+ autoWidth: true,
1544
+ }).data('kendoDropDownList');
1545
+
1546
+ this._banDurationIn = $('#znm-banDurationNS').kendoNumericTextBox({
1547
+ min: 1,
1548
+ step: 1,
1549
+ format: '#',
1550
+ placeholder: 'Duration'
1551
+ }).data('kendoNumericTextBox');
1552
+
1553
+ this._banDelayIn = $('#znm-banDelayNS').kendoNumericTextBox({
1554
+ min: 0,
1555
+ step: 1,
1556
+ format: '#',
1557
+ placeholder: 'Delay (s)'
1558
+ }).data('kendoNumericTextBox');
1559
+
1560
+ // Add button click listeners
1561
+ $('#znm-disconnectBt').on('click', $.proxy(this._onDisconnectBtClick, this));
1562
+ $('#znm-kickBt').on('click', $.proxy(this._onKickBtClick, this));
1563
+ $('#znm-banBt').on('click', $.proxy(this._onBanBtClick, this));
1564
+
1565
+ // Charts
1566
+
1567
+ this._packetQueueChart = $('#znm-packetQueueChart').kendoChart({
1568
+ transitions: false,
1569
+ chartArea: {
1570
+ height: 100
1571
+ },
1572
+ legend: {
1573
+ visible: false
1574
+ },
1575
+ seriesDefaults: {
1576
+ type: 'bar',
1577
+ labels: {
1578
+ visible: true,
1579
+ format: '{0}%',
1580
+ background: 'transparent',
1581
+ position: 'insideBase'
1582
+ },
1583
+ gap: .5,
1584
+ spacing: 0,
1585
+ overlay: {
1586
+ gradient: 'none'
1587
+ },
1588
+ border: {
1589
+ width: 0
1590
+ }
1591
+ },
1592
+ series: [
1593
+ {
1594
+ name: 'Packet queue',
1595
+ field: 'value',
1596
+ categoryField: 'category',
1597
+ color: '#FB7D33'
1598
+ }
1599
+ ],
1600
+ valueAxis: {
1601
+ labels: {
1602
+ format: '{0}%'
1603
+ },
1604
+ line: {
1605
+ visible: false
1606
+ },
1607
+ min: 0,
1608
+ max: 100
1609
+ },
1610
+ categoryAxis: {
1611
+ majorGridLines: {
1612
+ visible: false
1613
+ },
1614
+ majorTicks: {
1615
+ visible: false
1616
+ },
1617
+ labels: {
1618
+ visible: false
1619
+ }
1620
+ },
1621
+ tooltip: {
1622
+ visible: false,
1623
+ }
1624
+ }).data('kendoChart');
1625
+
1626
+ this._droppedMsgChart = $('#znm-droppedMsgChart').kendoChart({
1627
+ transitions: false,
1628
+ chartArea: {
1629
+ height: 100
1630
+ },
1631
+ legend: {
1632
+ visible: false
1633
+ },
1634
+ seriesDefaults: {
1635
+ type: 'bar',
1636
+ labels: {
1637
+ visible: true,
1638
+ format: '{0}',
1639
+ background: 'transparent',
1640
+ position: 'insideBase',
1641
+ },
1642
+ gap: .5,
1643
+ spacing: 0,
1644
+ overlay: {
1645
+ gradient: 'none'
1646
+ },
1647
+ border: {
1648
+ width: 0
1649
+ }
1650
+ },
1651
+ series: [
1652
+ {
1653
+ name: 'Dropped messages',
1654
+ field: 'value',
1655
+ categoryField: 'category',
1656
+ color: '#FB7D33'
1657
+ }
1658
+ ],
1659
+ valueAxis: {
1660
+ labels: {
1661
+ format: '{0}'
1662
+ },
1663
+ line: {
1664
+ visible: false
1665
+ },
1666
+ min: 0,
1667
+ },
1668
+ categoryAxis: {
1669
+ majorGridLines: {
1670
+ visible: false
1671
+ },
1672
+ majorTicks: {
1673
+ visible: false
1674
+ },
1675
+ labels: {
1676
+ visible: false
1677
+ }
1678
+ },
1679
+ tooltip: {
1680
+ visible: false,
1681
+ }
1682
+ }).data('kendoChart');
1683
+
1684
+ this._writtenDataChart = $('#znm-writtenDataChart').kendoChart({
1685
+ transitions: false,
1686
+ chartArea: {
1687
+ height: 100
1688
+ },
1689
+ legend: {
1690
+ visible: false
1691
+ },
1692
+ seriesDefaults: {
1693
+ type: 'bar',
1694
+ labels: {
1695
+ visible: true,
1696
+ format: '{0}',
1697
+ background: 'transparent',
1698
+ position: 'insideBase',
1699
+ template: Object(_components_charts_chart_utils__WEBPACK_IMPORTED_MODULE_7__["getWRBytesLabelTemplate"])(),
1700
+ },
1701
+ gap: .5,
1702
+ spacing: 0,
1703
+ overlay: {
1704
+ gradient: 'none'
1705
+ },
1706
+ border: {
1707
+ width: 0
1708
+ }
1709
+ },
1710
+ series: [
1711
+ {
1712
+ name: 'Written data',
1713
+ field: 'value',
1714
+ categoryField: 'category',
1715
+ color: '#FB7D33'
1716
+ }
1717
+ ],
1718
+ valueAxis: {
1719
+ labels: {
1720
+ format: '{0}'
1721
+ },
1722
+ line: {
1723
+ visible: false
1724
+ },
1725
+ min: 0,
1726
+ },
1727
+ categoryAxis: {
1728
+ majorGridLines: {
1729
+ visible: false
1730
+ },
1731
+ majorTicks: {
1732
+ visible: false
1733
+ },
1734
+ labels: {
1735
+ visible: false
1736
+ }
1737
+ },
1738
+ tooltip: {
1739
+ visible: false,
1740
+ }
1741
+ }).data('kendoChart');
1742
+
1743
+ this._readDataChart = $('#znm-readDataChart').kendoChart({
1744
+ transitions: false,
1745
+ chartArea: {
1746
+ height: 100
1747
+ },
1748
+ legend: {
1749
+ visible: false
1750
+ },
1751
+ seriesDefaults: {
1752
+ type: 'bar',
1753
+ labels: {
1754
+ visible: true,
1755
+ format: '{0}',
1756
+ background: 'transparent',
1757
+ position: 'insideBase',
1758
+ template: Object(_components_charts_chart_utils__WEBPACK_IMPORTED_MODULE_7__["getWRBytesLabelTemplate"])(),
1759
+ },
1760
+ gap: .5,
1761
+ spacing: 0,
1762
+ overlay: {
1763
+ gradient: 'none'
1764
+ },
1765
+ border: {
1766
+ width: 0
1767
+ }
1768
+ },
1769
+ series: [
1770
+ {
1771
+ name: 'Read data',
1772
+ field: 'value',
1773
+ categoryField: 'category',
1774
+ color: '#FB7D33'
1775
+ }
1776
+ ],
1777
+ valueAxis: {
1778
+ labels: {
1779
+ format: '{0}'
1780
+ },
1781
+ line: {
1782
+ visible: false
1783
+ },
1784
+ min: 0,
1785
+ },
1786
+ categoryAxis: {
1787
+ majorGridLines: {
1788
+ visible: false
1789
+ },
1790
+ majorTicks: {
1791
+ visible: false
1792
+ },
1793
+ labels: {
1794
+ visible: false
1795
+ }
1796
+ },
1797
+ tooltip: {
1798
+ visible: false,
1799
+ }
1800
+ }).data('kendoChart');
1801
+
1802
+ //-------------------------------
1803
+
1804
+ // Add listener to redraw all charts in case of window resize
1805
+ $(window).on('resize', $.proxy(this._onWindowResize, this));
1806
+ this._onWindowResize(); // Also do it immediately
1807
+
1808
+ // Request data to server
1809
+ this._requestData(true);
1810
+ }
1811
+
1812
+ destroy()
1813
+ {
1814
+ // Call super method
1815
+ super.destroy();
1816
+
1817
+ // Close monitoring
1818
+ this._onCloseMonitorBtClick();
1819
+
1820
+ // Remove doubleclick event listeners
1821
+ this._zoneListBox.wrapper.find('.k-list').off('dblclick');
1822
+ this._roomListBox.wrapper.find('.k-list').off('dblclick');
1823
+ this._userListBox.wrapper.find('.k-list').off('dblclick');
1824
+
1825
+ // Remove other event listeners
1826
+ $('#znm-createRoomBt').off('click');
1827
+ $('#znm-removeRoomBt').off('click');
1828
+ $('#znm-roomCreatorCreateBt').off('click');
1829
+ $('#znm-filterRoomBt').off('click');
1830
+ $('#znm-applyRoomFilterCB').off('change');
1831
+ $('#znm-filterUserBt').off('click');
1832
+ $('#znm-applyUserFilterCB').off('change');
1833
+ $('#znm-monitorBt').off('click');
1834
+ $('#znm-sendMessageBt').off('click');
1835
+ $('#znm-messageIn').off('keyup');
1836
+ $('#znm-closeMonitorBt').off('click');
1837
+ $('#znm-editBt').off('click');
1838
+ $('#znm-cancelBt').off('click');
1839
+ $('#znm-submitBt').off('click');
1840
+ $(window).off('resize');
1841
+ $('#znm-reloadWordsBt').off('click');
1842
+ $('#znm-reloadZoneExtBt').off('click');
1843
+ $('#znm-disconnectBt').off('click');
1844
+ $('#znm-kickBt').off('click');
1845
+ $('#znm-banBt').off('click');
1846
+
1847
+ // Clear request scheduling
1848
+ clearTimeout(this._requestTimer);
1849
+
1850
+ // Hide room creation panel
1851
+ $('#znm-createRoomModal').modal('hide');
1852
+
1853
+ // Remove room creation panel listener
1854
+ $('#znm-createRoomModal').off('hidden.bs.modal');
1855
+
1856
+ // Remove filter panels listeners
1857
+ $(this._roomFilter).off(this._roomFilter.EXPRESSION_UPDATED_EVENT);
1858
+ $(this._userFilter).off(this._userFilter.EXPRESSION_UPDATED_EVENT);
1859
+ }
1860
+
1861
+ onExtensionCommand(command, data)
1862
+ {
1863
+ // Data received
1864
+ if (command == this.RESP_DATA)
1865
+ {
1866
+ // We have to check if the response id corresponds to the current request id;
1867
+ // if not, the response is discarded as it refers to an outdatet request
1868
+ const responseId = data.getInt('id');
1869
+
1870
+ if (responseId == this._currentRequestId)
1871
+ {
1872
+ // --- ZONES LIST ---
1873
+ if (data.containsKey('zones'))
1874
+ {
1875
+ this._setZonesDataProvider(data.getSFSArray('zones'));
1876
+
1877
+ if (this._selectedZone)
1878
+ this._setScopeLabel();
1879
+ }
1880
+
1881
+ // --- ROOMS LIST ---
1882
+ if (data.containsKey('rooms'))
1883
+ {
1884
+ this._setGroupsDataProvider(data.getUtfStringArray('groups'));
1885
+
1886
+ // -------------------------------
1887
+
1888
+ // If a null rooms list is returned, the zone must have been deleted!
1889
+ if (!data.isNull('rooms'))
1890
+ {
1891
+ this._setRoomsDataProvider(data.getSFSArray('rooms'));
1892
+
1893
+ if (!this._selectedRoom)
1894
+ this._setScopeLabel();
1895
+
1896
+ // -------------------------------
1897
+
1898
+ // Show warning if the rooms list exceeds the server-side limit
1899
+ if (data.containsKey('rSize'))
1900
+ this._showLimitExceededWarning($('#znm-roomListWarning'), 'The received list is incomplete, because its size (' + data.getInt('rSize') + ' Rooms) exceeded this client\'s limit of ' + data.getInt('rLimit') + '; you should refine your search');
1901
+ else
1902
+ this._showLimitExceededWarning($('#znm-roomListWarning'), '');
1903
+ }
1904
+ else
1905
+ {
1906
+ if (this._activePanelType == 'room')
1907
+ {
1908
+ this._accordion.select('[data-item-type="zone"]');
1909
+ this._accordion.expand('[data-item-type="zone"]');
1910
+ this._onZoneSelected();
1911
+ this._onEntitiesPanelChange();
1912
+ }
1913
+ }
1914
+ }
1915
+
1916
+ // --- USERS LIST ---
1917
+ if (data.containsKey('users'))
1918
+ {
1919
+ // If a null users list is returned, the room must have been deleted!
1920
+ if (!data.isNull('users'))
1921
+ {
1922
+ this._setUsersDataProvider(data.getSFSArray('users'));
1923
+
1924
+ // Show warning if the users list exceeds the server-side limit
1925
+ if (data.containsKey('uSize'))
1926
+ this._showLimitExceededWarning($('#znm-userListWarning'), 'The received list is incomplete, because its size (' + data.getInt('uSize') + ' users) exceeds this client\'s limit of ' + data.getInt('uLimit') + '; you should refine your search');
1927
+ else
1928
+ this._showLimitExceededWarning($('#znm-userListWarning'), '');
1929
+ }
1930
+ else
1931
+ {
1932
+ if (this._activePanelType == 'user')
1933
+ {
1934
+ this._accordion.select('[data-item-type="room"]');
1935
+ this._accordion.expand('[data-item-type="room"]');
1936
+ this._onRoomSelected();
1937
+ this._onEntitiesPanelChange();
1938
+ }
1939
+ }
1940
+ }
1941
+
1942
+ // --- MONITORED DATA ---
1943
+ if (data.containsKey('monitored'))
1944
+ {
1945
+ const zone = data.getSFSObject('monitored').getUtfString('zone');
1946
+ const type = data.getSFSObject('monitored').getUtfString('type');
1947
+ const name = data.getSFSObject('monitored').getUtfString('name');
1948
+
1949
+ if (zone == this._monitoredZone && type == this._monitoredType && name == this._monitoredName)
1950
+ {
1951
+ if (!data.getSFSObject('monitored').isNull('params'))
1952
+ {
1953
+ const params = data.getSFSObject('monitored').getSFSArray('params');
1954
+
1955
+ this._setMonitoringInterface();
1956
+
1957
+ // Build interface
1958
+ if (!this._isEditing)
1959
+ {
1960
+ this._interfaceBuilder.buildInterface(params, `znm-${this._monitoredType}TabNavigator`, true);
1961
+
1962
+ if (!this._skipInitTabs)
1963
+ {
1964
+ $(`#znm-${this._monitoredType}TabNavigator #tabs`).scrollingTabs({
1965
+ bootstrapVersion: 4,
1966
+ scrollToTabEdge: true,
1967
+ enableSwiping: true,
1968
+ disableScrollArrowsOnFullyScrolled: true,
1969
+ cssClassLeftArrow: 'fa fa-chevron-left',
1970
+ cssClassRightArrow: 'fa fa-chevron-right'
1971
+ });
1972
+
1973
+ this._skipInitTabs = true;
1974
+
1975
+ // Set first tab panel as active
1976
+ this._interfaceBuilder.activateFirstTabPanel();
1977
+
1978
+ // Redraw time range slider to set its width
1979
+ this._timeSlider.resize();
1980
+
1981
+ // Add listener to redraw all charts on tab change
1982
+ // (to work around an issue with the chart resizing to default width when pane is hidden)
1983
+ $('a[data-toggle="tab"]').on('shown.bs.tab', $.proxy(this._onWindowResize, this));
1984
+ }
1985
+ }
1986
+
1987
+ // Disable categories
1988
+ let disabledCat = (data.getSFSObject('monitored').containsKey('exclude') ? data.getSFSObject('monitored').getUtfStringArray('exclude') : []);
1989
+
1990
+ for (let cat of disabledCat)
1991
+ {
1992
+ let navLink = $(`#znm-${this._monitoredType}TabNavigator #tabs #tab-${cat}`);
1993
+
1994
+ navLink.addClass('disabled');
1995
+ navLink.attr('tabindex', -1);
1996
+ navLink.attr('aria-disabled', true);
1997
+ }
1998
+
1999
+ if (this._monitoredType == this.MONITORED_TYPE_ZONE)
2000
+ this._showZoneTrafficData(data.getSFSObject('monitored').getSFSObject('traffic'));
2001
+
2002
+ if (this._monitoredType == this.MONITORED_TYPE_USER)
2003
+ {
2004
+ // Stats
2005
+ this._showUserStatsData(data.getSFSObject('monitored').getSFSObject('stats'));
2006
+
2007
+ // NPC
2008
+ const isNpc = data.getSFSObject('monitored').getBool('npc');
2009
+
2010
+ // Disable disconnect, kick and ban buttons
2011
+ $('#znm-disconnectBt').attr('disabled', isNpc);
2012
+ $('#znm-kickBt').attr('disabled', isNpc);
2013
+ $('#znm-banBt').attr('disabled', isNpc);
2014
+
2015
+ // Geo-location
2016
+ const geoLocData = data.getSFSObject('monitored').getSFSObject('geoLoc');
2017
+ this._setGeoLocationUI(geoLocData);
2018
+ }
2019
+ }
2020
+ else
2021
+ {
2022
+ // Show alert
2023
+ this.shellCtrl.showSimpleAlert(`The ${Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_4__["capitalizeFirst"])(this._monitoredType)} being monitored is no more available on the server, please select another one.`, false);
2024
+
2025
+ // Cancel monitoring
2026
+ this._onCloseMonitorBtClick();
2027
+ }
2028
+ }
2029
+ }
2030
+ }
2031
+ }
2032
+
2033
+ else if (command == this.RESP_UPDATE_ERROR)
2034
+ {
2035
+ if (data.getUtfString('zone') == this._monitoredZone
2036
+ && data.getUtfString('type') == this._monitoredType
2037
+ && data.getUtfString('name') == this._monitoredName)
2038
+ {
2039
+ // Show alert
2040
+ this.shellCtrl.showSimpleAlert(`Unable to update ${Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_4__["capitalizeFirst"])(this._monitoredType)} settings; the following error was reported: ${data.getUtfString('message')}.`);
2041
+ }
2042
+ }
2043
+
2044
+ else if (command == this.RESP_ROOM_CONFIG)
2045
+ {
2046
+ // Re-enable Create button
2047
+ $('#znm-createRoomBt').attr('disabled', false);
2048
+
2049
+ // Show Room creation panel
2050
+ this._showRoomCreationPanel(data.getSFSArray('settings'));
2051
+ }
2052
+
2053
+ else if (command == this.RESP_ROOM_CONFIG_ERROR)
2054
+ {
2055
+ // Re-enable Create button
2056
+ $('#znm-createRoomBt').attr('disabled', false);
2057
+
2058
+ // Show an alert
2059
+ this.shellCtrl.showSimpleAlert(data.getUtfString('error'));
2060
+ }
2061
+
2062
+ else if (command == this.RESP_ROOM_CREATED)
2063
+ {
2064
+ // Re-enable room creation panel
2065
+ this._enableCreateRoomPanel(true);
2066
+
2067
+ // Hide room creation panel
2068
+ $('#znm-createRoomModal').modal('hide');
2069
+
2070
+ // Update rooms list
2071
+ this._requestData(true);
2072
+ }
2073
+
2074
+ else if (command == this.RESP_ROOM_CREATION_ERROR)
2075
+ {
2076
+ // Display error message
2077
+ $('#znm-createRoomError').text(data.getUtfString('error'));
2078
+ $('#znm-createRoomError').show();
2079
+
2080
+ // Re-enable room creation panel
2081
+ this._enableCreateRoomPanel(true);
2082
+ }
2083
+
2084
+ // Unexpected error received
2085
+ // This error is returned in case something went wrong when retrieving the monitored entity parameters,
2086
+ // so we have to stop requesting the same entity
2087
+ else if (command == this.RESP_UNEXPECTED_ERROR)
2088
+ {
2089
+ // Cancel monitoring
2090
+ this._onCloseMonitorBtClick();
2091
+
2092
+ // Show an alert
2093
+ this.shellCtrl.showSimpleAlert(data.getUtfString('error'));
2094
+ }
2095
+
2096
+ // Extension (Zone or Room) log messages received
2097
+ else if (command == this.RESP_LOG_MESSAGES)
2098
+ {
2099
+ let logEntries = data.getSFSArray('entries');
2100
+
2101
+ for (let e = 0; e < logEntries.size(); e++)
2102
+ {
2103
+ let logEntry = logEntries.getSFSObject(e);
2104
+
2105
+ const logZone = logEntry.getUtfString('zone');
2106
+ const logRoom = logEntry.getUtfString('room');
2107
+
2108
+ // Check if the zone is currently monitored
2109
+ if (this._monitoredZone == logZone)
2110
+ {
2111
+ // console.log(logEntry.getLong('time'))
2112
+ // console.log(new Date(logEntry.getLong('time'))
2113
+
2114
+ let ele = {
2115
+ timestamp: kendo.toString(new Date(logEntry.getLong('time')), 'dd/MM/yyyy HH:mm:ss'),
2116
+ level: logEntry.getUtfString('level'),
2117
+ message: logEntry.getUtfString('msg'),
2118
+ };
2119
+
2120
+ if (this._monitoredType == this.MONITORED_TYPE_ZONE && logRoom == '')
2121
+ {
2122
+ // Add to zone extension log
2123
+ this._addLogEntryToGrid(this._zoneExtLogGrid, ele);
2124
+ }
2125
+ else
2126
+ {
2127
+ if (this._monitoredType == this.MONITORED_TYPE_ROOM && this._monitoredName == logRoom)
2128
+ {
2129
+ // Add to room extension log
2130
+ this._addLogEntryToGrid(this._roomExtLogGrid, ele);
2131
+ }
2132
+ }
2133
+ }
2134
+ }
2135
+ }
2136
+ }
2137
+
2138
+ //---------------------------------
2139
+ // UI EVENT LISTENERS
2140
+ //---------------------------------
2141
+
2142
+ _onUpdateIntervalChange()
2143
+ {
2144
+ // Request data to server
2145
+ this._requestData(false);
2146
+ }
2147
+
2148
+ _onEntitiesPanelChange()
2149
+ {
2150
+ // Set main controls state
2151
+ this._setMainControlsEnabled();
2152
+
2153
+ // Request data to server
2154
+ this._requestData(true);
2155
+ }
2156
+
2157
+ /**
2158
+ * Update the Scope label in the Rooms panel.
2159
+ */
2160
+ _onZoneSelected()
2161
+ {
2162
+ // Clear Room and User lists
2163
+ this._resetRoomList();
2164
+ this._resetUserList();
2165
+
2166
+ // Set scope label
2167
+ this._setScopeLabel();
2168
+
2169
+ // Enable/disable Room and User tools
2170
+ const disabled = this._selectedZone == undefined;
2171
+
2172
+ // (NOTE: this enables/disables whole fieldset; this doesn't affect Kendo DropDown, so we have to do it manually)
2173
+ $('#roomTools').attr('disabled', disabled);
2174
+ $('#userTools').attr('disabled', disabled);
2175
+
2176
+ this._groupsDropDown.enable(!disabled);
2177
+
2178
+ // Set main controls state
2179
+ this._setMainControlsEnabled();
2180
+ }
2181
+
2182
+ /**
2183
+ * Update the Scope label in the Users panel.
2184
+ */
2185
+ _onRoomSelected()
2186
+ {
2187
+ // Clear User list
2188
+ this._resetUserList();
2189
+
2190
+ // Set scope label
2191
+ this._setScopeLabel();
2192
+
2193
+ // Enable Remove button
2194
+ $('#znm-removeRoomBt').attr('disabled', this._selectedRoom == undefined);
2195
+
2196
+ // Set main controls state
2197
+ this._setMainControlsEnabled();
2198
+ }
2199
+
2200
+ /**
2201
+ * Update the scope label in the Users panel.
2202
+ */
2203
+ _onGroupChange()
2204
+ {
2205
+ // Clear Room and User lists
2206
+ this._resetRoomList();
2207
+ this._resetUserList();
2208
+
2209
+ // Set scope label
2210
+ this._setScopeLabel();
2211
+
2212
+ // Request data to server
2213
+ this._requestData(true);
2214
+
2215
+ // Set main controls state
2216
+ this._setMainControlsEnabled();
2217
+ }
2218
+
2219
+ _onUserSelected()
2220
+ {
2221
+ // Set main controls state
2222
+ this._setMainControlsEnabled();
2223
+ }
2224
+
2225
+ /**
2226
+ * Show room creation panel.
2227
+ */
2228
+ _onCreateRoomBtClick()
2229
+ {
2230
+ // Disable Create button
2231
+ $('#znm-createRoomBt').attr('disabled', true);
2232
+
2233
+ // Request default room settings to extension
2234
+ this.sendExtensionRequest(this.REQ_GET_ROOM_CONFIG);
2235
+ }
2236
+
2237
+ /**
2238
+ * Remove existing room.
2239
+ */
2240
+ _onRemoveRoomBtClick()
2241
+ {
2242
+ this.shellCtrl.showConfirmWarning('Are you sure you want to remove the selected Room?', $.proxy(this._onRemoveRemoveConfirm, this));
2243
+ }
2244
+
2245
+ _onRemoveRemoveConfirm()
2246
+ {
2247
+ const selectedZone = this._zoneListBox.dataItem(this._zoneListBox.select());
2248
+ let selectedRoom = this._roomListBox.dataItem(this._roomListBox.select());
2249
+
2250
+ if (selectedRoom)
2251
+ {
2252
+ // Send request to server
2253
+ let params = new SFS2X.SFSObject();
2254
+ params.putUtfString('zone', selectedZone.name);
2255
+ params.putUtfString('room', selectedRoom.name);
2256
+
2257
+ this.sendExtensionRequest(this.REQ_REMOVE_ROOM, params);
2258
+
2259
+ // Request data to server to update the rooms list
2260
+ this._requestData(true);
2261
+ }
2262
+ }
2263
+
2264
+ /**
2265
+ * Remove content of room creation panel.
2266
+ */
2267
+ _onCreateRoomModalHidden(e)
2268
+ {
2269
+ // If a nested modal is opened, its closing causes the parent modal to be closed too (Bootstrap doesn't support nested modals)
2270
+ // As a workaround, here we reset the css class 'modal-open' when the nested modal is closed and skip everything else
2271
+ // In addition we had to use a custom listener on the close/cancel buttons of the nested modal (see config-grid.js for example)
2272
+ if (e.target !== document.getElementById('znm-createRoomModal'))
2273
+ {
2274
+ $('body').addClass('modal-open')
2275
+ return;
2276
+ }
2277
+
2278
+ // Destroy scrolling tabs in room creation panel
2279
+ $('#znm-roomCreatorTabNav #tabs').scrollingTabs('destroy');
2280
+
2281
+ // Remove all tab navigator content
2282
+ this._roomCreationIBuilder.destroyInterface();
2283
+
2284
+ // Remove listener for custom actions triggered by configuration interface
2285
+ $('#znm-roomCreatorTabNav').off('value-set');
2286
+
2287
+ // Reset and hide error message
2288
+ this._resetRoomCreationError();
2289
+ }
2290
+
2291
+ _onConfigValueSet(e) // SAME METHOD DUPLICATED IN zone-configurator.js
2292
+ {
2293
+ const configParam = e.target.data;
2294
+
2295
+ // Handle extension name/type dropdowns update and update the main class dropdown datasource accordingly
2296
+ if (configParam.name == 'extension.name' || configParam.name == 'extension.type' || configParam.name == 'extension.filterClass')
2297
+ {
2298
+ // All involved ConfigFormItems must be available and initialized to proceed
2299
+ const nameFormItem = this._roomCreationIBuilder.getConfigFormItem('extension.name');
2300
+ const typeFormItem = this._roomCreationIBuilder.getConfigFormItem('extension.type');
2301
+ const classFormItem = this._roomCreationIBuilder.getConfigFormItem('extension.file');
2302
+ const filterFormItem = this._roomCreationIBuilder.getConfigFormItem('extension.filterClass');
2303
+
2304
+ if (nameFormItem != null && typeFormItem != null && classFormItem != null && filterFormItem != null)
2305
+ {
2306
+ const source = nameFormItem.data;
2307
+ let classesList = [];
2308
+
2309
+ let data = source.triggerData;
2310
+ for (let i = 0; i < data.size(); i++)
2311
+ {
2312
+ let ext = data.getSFSObject(i);
2313
+
2314
+ if (ext.getUtfString('name') == nameFormItem.data.value && ext.getUtfString('type') == typeFormItem.data.value)
2315
+ {
2316
+ let classes = ext.get('classesString').split(','); // We don't use "getUTfString" because the type is Text in case a very large list of classes is returned
2317
+
2318
+ if (filterFormItem.data.value == true)
2319
+ {
2320
+ let filteredClasses = classes.filter(_utils_utilities__WEBPACK_IMPORTED_MODULE_4__["filterClassName"]);
2321
+ classes = filteredClasses;
2322
+ }
2323
+
2324
+ classesList = classesList.concat(classes);
2325
+ }
2326
+ }
2327
+
2328
+ let currentClass = classFormItem.data.value;
2329
+
2330
+ // If the classes list doesn't contain the current value, create an empty entry and reset the value
2331
+ if (classesList.indexOf(currentClass) < 0)
2332
+ {
2333
+ if (classesList.length == 0)
2334
+ {
2335
+ classesList.push('');
2336
+ currentClass = '';
2337
+ }
2338
+ else
2339
+ currentClass = classesList[0];
2340
+ }
2341
+
2342
+ let mainClassDropDown = classFormItem._innerWidget;
2343
+ mainClassDropDown.setDataSource(classesList);
2344
+
2345
+ classFormItem.data.value = currentClass;
2346
+ classFormItem._setWidgetValue();
2347
+ }
2348
+ }
2349
+ }
2350
+
2351
+ _onRoomCreatorCreateBtClick()
2352
+ {
2353
+ // Reset and hide error message
2354
+ this._resetRoomCreationError();
2355
+
2356
+ // Check validity
2357
+ if (this._roomCreationIBuilder.checkIsValid())
2358
+ {
2359
+ let changes = this._roomCreationIBuilder.getChangedData();
2360
+
2361
+ if (changes.size() > 0)
2362
+ {
2363
+ // Check the room name against the rooms list (duplicate names not allowed!)
2364
+ if (true)//this._validateNewRoomName(changes))
2365
+ {
2366
+ // Disable room creation panel
2367
+ this._enableCreateRoomPanel(false);
2368
+
2369
+ // Send settings to server instance
2370
+ let params = new SFS2X.SFSObject();
2371
+ params.putSFSArray('settings', changes);
2372
+ params.putUtfString('zName', this._zoneListBox.dataItem(this._zoneListBox.select()).name);
2373
+ params.putBool('notify', $('#znm-notifyClientsCB').prop('checked'));
2374
+
2375
+ // Send settings to extension
2376
+ this.sendExtensionRequest(this.REQ_CREATE_ROOM, params);
2377
+ }
2378
+ else
2379
+ {}
2380
+ }
2381
+ }
2382
+ else
2383
+ {
2384
+ // Show alert
2385
+ this.shellCtrl.showSimpleAlert('Unable to submit Room configuration due to an invalid value; please verify the highlighted form fields in all tabs.', true);
2386
+ }
2387
+ }
2388
+
2389
+ _onShowRoomFilterBtClick()
2390
+ {
2391
+ this._roomFilter.show();
2392
+ }
2393
+
2394
+ _onShowUserFilterBtClick()
2395
+ {
2396
+ this._userFilter.show();
2397
+ }
2398
+
2399
+ _onApplyBtChange()
2400
+ {
2401
+ // Request data to server
2402
+ this._requestData(true);
2403
+ }
2404
+
2405
+ _onRoomFilterUpdated()
2406
+ {
2407
+ // Enable/disable "Apply" checkbox
2408
+ $('#znm-applyRoomFilterCB').attr('disabled', this._roomFilter.filterExpression == null);
2409
+
2410
+ // Request data to server
2411
+ this._requestData(true);
2412
+ }
2413
+
2414
+ _onUserFilterUpdated()
2415
+ {
2416
+ // Enable/disable "Apply" checkbox
2417
+ $('#znm-applyUserFilterCB').attr('disabled', this._userFilter.filterExpression == null);
2418
+
2419
+ // Request data to server
2420
+ this._requestData(true);
2421
+ }
2422
+
2423
+ _onMonitorSelectionBtClick()
2424
+ {
2425
+ if (this._selectedZone)
2426
+ {
2427
+ // Cancel previous monitoring
2428
+ this._onCloseMonitorBtClick();
2429
+
2430
+ let getZoneUserCountHistory = false;
2431
+
2432
+ this._monitoredZone = this._selectedZone.name;
2433
+
2434
+ // Zone must be monitored
2435
+ if (this._activePanelType == 'zone')
2436
+ {
2437
+ this._monitoredType = this.MONITORED_TYPE_ZONE;
2438
+ this._monitoredName = this._monitoredZone;
2439
+
2440
+ getZoneUserCountHistory = true;
2441
+ }
2442
+
2443
+ // Room must be monitored
2444
+ if (this._activePanelType == 'room' && this._selectedRoom != undefined)
2445
+ {
2446
+ this._monitoredType = this.MONITORED_TYPE_ROOM;
2447
+ this._monitoredName = this._selectedRoom.name;
2448
+ }
2449
+
2450
+ // User must be monitored
2451
+ if (this._activePanelType == 'user' && this._selectedUser != undefined)
2452
+ {
2453
+ this._monitoredType = this.MONITORED_TYPE_USER;
2454
+ this._monitoredName = this._selectedUser.name;
2455
+ }
2456
+
2457
+ // Show loading bar
2458
+ this._switchView('znm-loading');
2459
+
2460
+ // Request data to server
2461
+ this._requestData(true, getZoneUserCountHistory);
2462
+ }
2463
+ }
2464
+
2465
+ _onSendAdminMsgInKeyUp(event)
2466
+ {
2467
+ if (event.key !== 'Enter')
2468
+ return;
2469
+
2470
+ event.preventDefault();
2471
+ this._onSendAdminMsgBtClick();
2472
+ }
2473
+
2474
+ _onSendAdminMsgBtClick()
2475
+ {
2476
+ if (this._selectedZone && $('#znm-messageIn').val() != '')
2477
+ {
2478
+ // Build request parameters
2479
+ let params = new SFS2X.SFSObject();
2480
+
2481
+ // Always include zone
2482
+ params.putUtfString('zone', this._selectedZone.name);
2483
+
2484
+ // Send message to room?
2485
+ if (this._activePanelType == 'room' && this._selectedRoom != undefined)
2486
+ params.putUtfString('room', this._selectedRoom.name);
2487
+
2488
+ // Send message to user?
2489
+ if (this._activePanelType == 'user' && this._selectedUser != undefined)
2490
+ params.putUtfString('user', this._selectedUser.name);
2491
+
2492
+ // Add message
2493
+ params.putUtfString('msg', $('#znm-messageIn').val());
2494
+
2495
+ // Send request to extension
2496
+ this.sendExtensionRequest(this.REQ_ADMIN_MSG, params);
2497
+
2498
+ // Clear text input
2499
+ $('#znm-messageIn').val('');
2500
+ }
2501
+ }
2502
+
2503
+ _onCloseMonitorBtClick()
2504
+ {
2505
+ // Save ref. for later usage
2506
+ const monitoredType = this._monitoredType;
2507
+
2508
+ this._monitoredZone = null;
2509
+ this._monitoredType = null;
2510
+ this._monitoredName = null;
2511
+
2512
+ // Clear geolocation UI
2513
+ this._clearGeoLocationUI();
2514
+
2515
+ // Clear log datagrids dataproviders
2516
+ // NOTE: a try-catch is used here because, for an unknown reason, Kendo is throwing an error when resetting the data sources when the module is destroyed
2517
+ try
2518
+ {
2519
+ this._zoneExtLogGrid.setDataSource([]);
2520
+ this._roomExtLogGrid.setDataSource([]);
2521
+ }
2522
+ catch (e) { /* Ignore */ }
2523
+
2524
+ // Leave edit mode
2525
+ this._onCancelBtClick();
2526
+
2527
+ // Rearrange monitoring interface
2528
+ this._setMonitoringInterface();
2529
+
2530
+ // Clear tab navigator
2531
+ this._clearTabs(monitoredType);
2532
+ }
2533
+
2534
+ _onEditBtClick()
2535
+ {
2536
+ if (!this._isEditing)
2537
+ {
2538
+ // Show edit controls
2539
+ $('#znm-editControls').show();
2540
+
2541
+ // Hide edit button
2542
+ $('#znm-editBt').hide();
2543
+
2544
+ // Enable editable fields
2545
+ this._interfaceBuilder.disableInterface(false);
2546
+
2547
+ this._isEditMode = true;
2548
+ }
2549
+ }
2550
+
2551
+ _onCancelBtClick()
2552
+ {
2553
+ if (this._isEditing)
2554
+ {
2555
+ // Hide edit controls
2556
+ $('#znm-editControls').hide();
2557
+
2558
+ // Show edit button
2559
+ $('#znm-editBt').show();
2560
+
2561
+ // Disable editable fields
2562
+ this._interfaceBuilder.disableInterface(true);
2563
+
2564
+ this._isEditMode = false;
2565
+
2566
+ // Hide validation messages
2567
+ this._interfaceBuilder.resetValidation();
2568
+
2569
+ // Request data to update interface (updating suspended in edit mode)
2570
+ this._requestData(true);
2571
+ }
2572
+ }
2573
+
2574
+ _onSubmitBtClick()
2575
+ {
2576
+ if (this._isEditing)
2577
+ {
2578
+ // Check validity
2579
+ if (this._interfaceBuilder.checkIsValid())
2580
+ {
2581
+ let changes = this._interfaceBuilder.getChangedData();
2582
+
2583
+ if (changes.size() > 0)
2584
+ {
2585
+ //console.log(changes.getDump())
2586
+
2587
+ // Send settings to server instance
2588
+ let params = new SFS2X.SFSObject();
2589
+ params.putSFSArray('settings', changes);
2590
+ params.putUtfString('zone', this._monitoredZone);
2591
+
2592
+ if (this._monitoredType == this.MONITORED_TYPE_ROOM)
2593
+ {
2594
+ // Submit room settings
2595
+ params.putUtfString('room', this._monitoredName);
2596
+ this.sendExtensionRequest(this.REQ_SET_ROOM_SETTINGS, params);
2597
+ }
2598
+ else if (this._monitoredType == this.MONITORED_TYPE_USER)
2599
+ {
2600
+ // Submit user settings
2601
+ params.putUtfString('user', this._monitoredName);
2602
+ this.sendExtensionRequest(this.REQ_SET_USER_SETTINGS, params);
2603
+ }
2604
+ else
2605
+ {
2606
+ // Submit zone settings
2607
+ this.sendExtensionRequest(this.REQ_SET_ZONE_SETTINGS, params);
2608
+ }
2609
+
2610
+ // Leave edit mode
2611
+ this._onCancelBtClick();
2612
+ }
2613
+ }
2614
+ else
2615
+ {
2616
+ // Show alert
2617
+ this.shellCtrl.showSimpleAlert('Unable to submit changes due to an invalid value; please verify the highlighted form fields in all tabs.', true);
2618
+ }
2619
+ }
2620
+ }
2621
+
2622
+ _onTimeRangeChange()
2623
+ {
2624
+ let values = this._timeSlider.value();
2625
+
2626
+ if (values[0] == values[1])
2627
+ {
2628
+ if (values[1] == -24)
2629
+ values[1] = -23;
2630
+
2631
+ values[0] = values[1] - 1;
2632
+
2633
+ // Reset the time range slider value (we need to use setTimeout
2634
+ // bacause doing it in the change event listener doesn't redraw the slider)
2635
+ setTimeout($.proxy( function(values) { this._timeSlider.value(values); }, this), 10, values);
2636
+ }
2637
+
2638
+ this._userCountChart.range = values;
2639
+ }
2640
+
2641
+ _onWindowResize()
2642
+ {
2643
+ // Redraw charts
2644
+ this._userCountChart.redraw();
2645
+ this._packetQueueChart.redraw();
2646
+ this._droppedMsgChart.redraw();
2647
+ this._writtenDataChart.redraw();
2648
+ this._readDataChart.redraw();
2649
+
2650
+ // Redraw time range slider
2651
+ this._timeSlider.resize();
2652
+ }
2653
+
2654
+ _onWordsReloadBtClick()
2655
+ {
2656
+ if (this._monitoredType == this.MONITORED_TYPE_ZONE)
2657
+ {
2658
+ // Send request to extension
2659
+ let params = new SFS2X.SFSObject();
2660
+ params.putUtfString('zone', this._monitoredName);
2661
+
2662
+ this.sendExtensionRequest(this.REQ_RELOAD_WORDS, params);
2663
+ }
2664
+ }
2665
+
2666
+ _onZoneExtReloadBtClick()
2667
+ {
2668
+ if (this._monitoredType == this.MONITORED_TYPE_ZONE)
2669
+ {
2670
+ // Send request to extension
2671
+ let params = new SFS2X.SFSObject();
2672
+ params.putUtfString('zone', this._monitoredName);
2673
+
2674
+ this.sendExtensionRequest(this.REQ_RELOAD_ZONE_EXT, params);
2675
+ }
2676
+ }
2677
+
2678
+ _onDisconnectBtClick()
2679
+ {
2680
+ if (this._monitoredType == this.MONITORED_TYPE_USER)
2681
+ {
2682
+ // Send request to extension
2683
+ let params = new SFS2X.SFSObject();
2684
+ params.putUtfString('zone', this._monitoredZone);
2685
+ params.putUtfString('user', this._monitoredName);
2686
+
2687
+ this.sendExtensionRequest(this.REQ_DISCONNECT_USER, params);
2688
+ }
2689
+ }
2690
+
2691
+ _onKickBtClick()
2692
+ {
2693
+ if (this._monitoredType == this.MONITORED_TYPE_USER)
2694
+ {
2695
+ // Send request to extension
2696
+ let params = new SFS2X.SFSObject();
2697
+ params.putUtfString('zone', this._monitoredZone);
2698
+ params.putUtfString('user', this._monitoredName);
2699
+ params.putUtfString('msg', $('#znm-kickMsgIn').val());
2700
+ params.putInt('delay', (this._kickDelayIn.value() != null ? Number(this._kickDelayIn.value()) : this.KICK_BAN_DEFAULT_DELAY));
2701
+
2702
+ this.sendExtensionRequest(this.REQ_KICK_USER, params);
2703
+
2704
+ // Reset message
2705
+ $('#znm-kickMsgIn').val('');
2706
+ }
2707
+ }
2708
+
2709
+ _onBanBtClick()
2710
+ {
2711
+ if (this._monitoredType == this.MONITORED_TYPE_USER)
2712
+ {
2713
+ // Send request to extension
2714
+ let params = new SFS2X.SFSObject();
2715
+ params.putUtfString('zone', this._monitoredZone);
2716
+ params.putUtfString('user', this._monitoredName);
2717
+ params.putUtfString('msg', $('#znm-banMsgIn').val());
2718
+ params.putUtfString('rsn', $('#znm-banRsnIn').val());
2719
+ params.putUtfString('mode', this._banModeDd.select() > 0 ? this._banModeDd.value() : 'NAME');
2720
+ params.putInt('delay', (this._banDelayIn.value() != null ? Number(this._banDelayIn.value()) : this.KICK_BAN_DEFAULT_DELAY));
2721
+
2722
+ let duration = this._banDurationIn.value() != null ? Number(this._banDurationIn.value()) : 1;
2723
+
2724
+ if (this._banDurUnitDd.value() == 'hours')
2725
+ duration = duration * 60;
2726
+ else if (this._banDurUnitDd.value() == 'days')
2727
+ duration = duration * 60 * 24;
2728
+
2729
+ params.putInt('duration', duration);
2730
+
2731
+ this.sendExtensionRequest(this.REQ_BAN_USER, params);
2732
+
2733
+ // Reset message and reason
2734
+ $('#znm-banMsgIn').val('');
2735
+ $('#znm-banRsnIn').val('');
2736
+ }
2737
+ }
2738
+
2739
+ //------------------------------------
2740
+ // PRIVATE METHODS
2741
+ //------------------------------------
2742
+
2743
+ _setMonitoringInterface()
2744
+ {
2745
+ const enabled = (this._monitoredType != null && this._monitoredName != null);
2746
+
2747
+ // Show/hide header and footer
2748
+ if (enabled)
2749
+ {
2750
+ this._switchView(`znm-${this._monitoredType}Monitor`);
2751
+
2752
+ // Header title
2753
+ let title = 'Now monitoring ';
2754
+
2755
+ if (this._monitoredType == this.MONITORED_TYPE_USER)
2756
+ title += `User: <strong>${this._monitoredName}</strong> (Zone: ${this._monitoredZone})`;
2757
+ else if (this._monitoredType == this.MONITORED_TYPE_ROOM)
2758
+ title += `Room: <strong>${this._monitoredName}</strong> (Zone: ${this._monitoredZone})`;
2759
+ else
2760
+ title += `Zone: <strong>${this._monitoredZone}</strong>`;
2761
+
2762
+ $('#znm-monitoredHeader').html(title);
2763
+ $('#znm-monitoredFooter').show();
2764
+
2765
+ // Show panel
2766
+ this._switchPanel('znm-mainPanel');
2767
+ }
2768
+ else
2769
+ {
2770
+ this._switchView('znm-select');
2771
+
2772
+ $('#znm-monitoredHeader').html('');
2773
+ $('#znm-monitoredFooter').hide();
2774
+
2775
+ // Show panel
2776
+ this._switchPanel('znm-sidebarPanel');
2777
+ }
2778
+ }
2779
+
2780
+ _switchView(viewId)
2781
+ {
2782
+ document.getElementById('znm-viewstack').selectedElement = document.getElementById(viewId);
2783
+ }
2784
+
2785
+ _switchPanel(panelId)
2786
+ {
2787
+ document.getElementById('znm-view').selectedPanel = document.getElementById(panelId);
2788
+ }
2789
+
2790
+ /**
2791
+ * Build the polling request to be sent to the server, based on the selections and other settings in the accordion.
2792
+ */
2793
+ _requestData(newId = false, getZoneUserCountHistory = false)
2794
+ {
2795
+ // Clear previous request scheduling
2796
+ clearTimeout(this._requestTimer);
2797
+
2798
+ // Check if connection is still available
2799
+ if (this.smartFox.isConnected)
2800
+ {
2801
+ if (newId)
2802
+ this._currentRequestId++;
2803
+
2804
+ // Build request parameters
2805
+ let params = new SFS2X.SFSObject();
2806
+
2807
+ // The updated zones/rooms/users lists are requested if the corresponding panel is displayed only
2808
+ const getZones = (this._activePanelType == 'zone');
2809
+ const getRooms = (this._activePanelType == 'room' && this._selectedZone != undefined);
2810
+ const getUsers = (this._activePanelType == 'user' && this._selectedZone != undefined);
2811
+
2812
+ // --- ZONES ---
2813
+ params.putBool('zones', getZones);
2814
+
2815
+ // ROOMS & USERS
2816
+ if (getRooms || getUsers)
2817
+ {
2818
+ // Common filtering params:
2819
+
2820
+ // a) zone name
2821
+ params.putUtfString('zone', this._selectedZone.name);
2822
+
2823
+ // b) group name
2824
+ params.putUtfString('group', this._selectedGroup.name);
2825
+ }
2826
+
2827
+ // ROOMS
2828
+ params.putBool('rooms', getRooms);
2829
+ if (getRooms)
2830
+ {
2831
+ // Filtering params:
2832
+
2833
+ // c) advanced filtering params
2834
+ if ($('#znm-applyRoomFilterCB').prop('checked') && this._roomFilter.filterExpression != null)
2835
+ params.putSFSArray('rFilter', this._roomFilter.filterExpression.toSFSArray());
2836
+ }
2837
+
2838
+ // USERS
2839
+ params.putBool('users', getUsers);
2840
+ if (getUsers)
2841
+ {
2842
+ // Filtering params:
2843
+
2844
+ // c) room name
2845
+ if (this._selectedRoom)
2846
+ params.putUtfString('room', this._selectedRoom.name);
2847
+
2848
+ // d) advanced filtering params
2849
+ if ($('#znm-applyUserFilterCB').prop('checked') && this._userFilter.filterExpression != null)
2850
+ params.putSFSArray('uFilter', this._userFilter.filterExpression.toSFSArray());
2851
+ }
2852
+
2853
+ // --- CURRENTLY MONITORED DATA ---
2854
+ if (this._monitoredType != null && this._monitoredName != null)
2855
+ {
2856
+ let monitoredObj = this._getBasicMonitoredObject();
2857
+
2858
+ if (this._monitoredType == this.MONITORED_TYPE_ZONE)
2859
+ monitoredObj.putBool('uc', getZoneUserCountHistory);
2860
+
2861
+ params.putSFSObject('monitored', monitoredObj);
2862
+ }
2863
+
2864
+ // Set request id; when a response is received, we check its id matches the current request id: if not, the response is discarded
2865
+ params.putInt('id', this._currentRequestId);
2866
+
2867
+ // Send request to extension
2868
+ this.sendExtensionRequest(this.REQ_GET_DATA, params);
2869
+
2870
+ // Schedule next request
2871
+ this._requestTimer = setTimeout($.proxy(this._requestData, this), Number(this._intervalDropDown.value()) * 1000);
2872
+ }
2873
+ }
2874
+
2875
+ _getBasicMonitoredObject()
2876
+ {
2877
+ let monitoredObj = new SFS2X.SFSObject();
2878
+
2879
+ monitoredObj.putUtfString('zone', this._monitoredZone);
2880
+ monitoredObj.putUtfString('type', this._monitoredType);
2881
+ monitoredObj.putUtfString('name', this._monitoredName);
2882
+
2883
+ return monitoredObj;
2884
+ }
2885
+
2886
+ _setZonesDataProvider(zonesData)
2887
+ {
2888
+ this._setListDataProvider(this._zoneListBox, zonesData, true);
2889
+ }
2890
+
2891
+ _setRoomsDataProvider(roomsData)
2892
+ {
2893
+ this._setListDataProvider(this._roomListBox, roomsData, true);
2894
+
2895
+ // Set Remove button state
2896
+ $('#znm-removeRoomBt').attr('disabled', this._selectedRoom == undefined);
2897
+ }
2898
+
2899
+ _setUsersDataProvider(usersData)
2900
+ {
2901
+ this._setListDataProvider(this._userListBox, usersData);
2902
+ }
2903
+
2904
+ _setListDataProvider(listWidget, listData, countUsers = false)
2905
+ {
2906
+ // Save reference to selected item name
2907
+ // NOTE: as we are substituting the whole data source, we need it to re-select the same item after update
2908
+ let selectedDataItem = listWidget.dataItem(listWidget.select());
2909
+ let selectedDataItemName = selectedDataItem ? selectedDataItem.name : null;
2910
+
2911
+ let dataArray = [];
2912
+
2913
+ // Convert data coming from server
2914
+ for (let i = 0; i < listData.size(); i++)
2915
+ {
2916
+ let itemData = listData.getSFSObject(i);
2917
+
2918
+ let item = {};
2919
+ item.name = itemData.getUtfString('name');
2920
+
2921
+ if (countUsers)
2922
+ item.users = itemData.getInt('users');
2923
+
2924
+ dataArray.push(item);
2925
+ }
2926
+
2927
+ // Create new data source
2928
+ let listDS = new kendo.data.DataSource({
2929
+ data: dataArray,
2930
+ schema: {
2931
+ model: {
2932
+ id: 'name'
2933
+ }
2934
+ },
2935
+ sort: {
2936
+ field: 'name',
2937
+ dir: 'asc'
2938
+ }
2939
+ });
2940
+
2941
+ // Assign data source to list
2942
+ listWidget.setDataSource(listDS);
2943
+
2944
+ // Select again previously selected item
2945
+ if (selectedDataItemName != null)
2946
+ {
2947
+ selectedDataItem = listDS.get(selectedDataItemName);
2948
+
2949
+ if (selectedDataItem)
2950
+ {
2951
+ let selectedElement = listWidget.wrapper.find('[data-uid="' + selectedDataItem.uid + '"]');
2952
+ listWidget.select(selectedElement);
2953
+ }
2954
+ }
2955
+
2956
+ // Reset main control state
2957
+ this._setMainControlsEnabled();
2958
+ }
2959
+
2960
+ _setGroupsDataProvider(groupsData)
2961
+ {
2962
+ // Create Groups array, adding common entries
2963
+ let groupsArray = [
2964
+ this._getGroupObj('', this.ANY_LABEL),
2965
+ this._getGroupObj(this.DEFAULT_GROUP_NAME)
2966
+ ];
2967
+
2968
+ // Save reference to selected group name
2969
+ // NOTE: as we are substituting the whole data source, we need it to re-select the same item after update
2970
+ let selectedDataItem = this._selectedGroup;
2971
+ let selectedDataItemName = selectedDataItem ? selectedDataItem.name : null;
2972
+
2973
+ if (groupsData != null)
2974
+ {
2975
+ for (let i = 0; i < groupsData.length; i++)
2976
+ {
2977
+ if (groupsData[i] != this.DEFAULT_GROUP_NAME) // Default group was added before
2978
+ groupsArray.push(this._getGroupObj(groupsData[i]));
2979
+ }
2980
+ }
2981
+
2982
+ // Create new data source
2983
+ let groupDS = new kendo.data.DataSource({
2984
+ data: groupsArray,
2985
+ schema: {
2986
+ model: {
2987
+ id: 'name'
2988
+ }
2989
+ }
2990
+ });
2991
+
2992
+ // Assign data source to dropdown
2993
+ this._groupsDropDown.setDataSource(groupDS);
2994
+
2995
+ //--------------------------------
2996
+
2997
+ // Select previously selected item
2998
+ selectedDataItem = groupDS.get(selectedDataItemName);
2999
+
3000
+ // If group is not found, select the default one
3001
+ if (selectedDataItem == undefined)
3002
+ selectedDataItem = groupDS.get(this.DEFAULT_GROUP_NAME);
3003
+
3004
+ this._groupsDropDown.select(function(dataItem) {
3005
+ return dataItem.name === selectedDataItem.name;
3006
+ });
3007
+ }
3008
+
3009
+ _getGroupObj(name, label = null)
3010
+ {
3011
+ return {
3012
+ name: name,
3013
+ label: (label != null ? label : name)
3014
+ }
3015
+ }
3016
+
3017
+ /**
3018
+ * Update the Scope label in the Rooms panel and in the Users panel.
3019
+ */
3020
+ _setScopeLabel()
3021
+ {
3022
+ let roomScope = '';
3023
+ let userScope = '';
3024
+
3025
+ if (this._selectedZone)
3026
+ {
3027
+ let zoneName = this._selectedZone.name;
3028
+ roomScope = this._getScopeLabelPart('Zone:', zoneName);
3029
+
3030
+ let selectedGroup = this._selectedGroup;
3031
+ let groupName = (selectedGroup && selectedGroup.name != '') ? selectedGroup.name : this.ANY_LABEL;
3032
+ let roomName = (this._selectedRoom) ? this._selectedRoom.name : this.ANY_LABEL;
3033
+
3034
+ userScope = this._getScopeLabelPart('Zone:', zoneName) + '<br>' + this._getScopeLabelPart('Group:', groupName) + '<br>' + this._getScopeLabelPart('Room:', roomName);
3035
+ }
3036
+
3037
+ $('#znm-roomScopeLb').html(roomScope);
3038
+ $('#znm-userScopeLb').html(userScope);
3039
+ }
3040
+
3041
+ _getScopeLabelPart(label, text)
3042
+ {
3043
+ return `<span class="text-muted">${label}</span> <span>${text}</span>`;
3044
+ }
3045
+
3046
+ _resetRoomList()
3047
+ {
3048
+ this._roomListBox.setDataSource([]);
3049
+
3050
+ // Also disable Remove button
3051
+ $('#znm-removeRoomBt').attr('disabled', true);
3052
+ }
3053
+
3054
+ _resetUserList()
3055
+ {
3056
+ this._userListBox.setDataSource([]);
3057
+ }
3058
+
3059
+ _setMainControlsEnabled()
3060
+ {
3061
+ let enabled = (this._activePanelType == 'zone' && this._selectedZone != undefined)
3062
+ || (this._activePanelType == 'room' && this._selectedRoom != undefined)
3063
+ || (this._activePanelType == 'user' && this._selectedUser != undefined);
3064
+
3065
+ $('#znm-mainControls').attr('disabled', !enabled);
3066
+
3067
+ $('#znm-monitorTargetLb').text(enabled ? Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_4__["capitalizeFirst"])(this._activePanelType) : 'selection');
3068
+ $('#znm-messageIn').attr('placeholder', 'Message to ' + (enabled ? Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_4__["capitalizeFirst"])(this._activePanelType) : 'selection'));
3069
+ }
3070
+
3071
+ _showLimitExceededWarning(icon, title)
3072
+ {
3073
+ icon.attr('title', title);
3074
+
3075
+ if (title != '')
3076
+ icon.removeClass('hidden');
3077
+ else
3078
+ icon.addClass('hidden');
3079
+ }
3080
+
3081
+ _showRoomCreationPanel(roomSettings)
3082
+ {
3083
+ // Build user interface based on passed data
3084
+ this._roomCreationIBuilder.buildInterface(roomSettings, 'znm-roomCreatorTabNav', false, 'rc');
3085
+
3086
+ // Enable scrolling tabs
3087
+ $('#znm-roomCreatorTabNav > #tabs').scrollingTabs({
3088
+ bootstrapVersion: 4,
3089
+ scrollToTabEdge: true,
3090
+ enableSwiping: true,
3091
+ disableScrollArrowsOnFullyScrolled: true,
3092
+ cssClassLeftArrow: 'fa fa-chevron-left',
3093
+ cssClassRightArrow: 'fa fa-chevron-right'
3094
+ });
3095
+
3096
+ // Reset Notify clients checkbox
3097
+ $('#znm-notifyClientsCB').prop('checked', true);
3098
+
3099
+ // Set listener for custom actions triggered by configuration interface
3100
+ $('#znm-roomCreatorTabNav').on('value-set', $.proxy(this._onConfigValueSet, this));
3101
+
3102
+ // Display panel
3103
+ $('#znm-createRoomModal').modal('show');
3104
+
3105
+ // Reset and hide error message
3106
+ this._resetRoomCreationError();
3107
+ }
3108
+
3109
+ _resetRoomCreationError()
3110
+ {
3111
+ // Reset and hide error message
3112
+ $('#znm-createRoomError').text('');
3113
+ $('#znm-createRoomError').hide();
3114
+ }
3115
+
3116
+ _validateNewRoomName(changes)
3117
+ {
3118
+ for (let i = 0; i < changes.size(); i++)
3119
+ {
3120
+ const setting = changes.getSFSObject(i);
3121
+
3122
+ if (setting.containsKey('name') && setting.getUtfString('name') == 'name')
3123
+ {
3124
+ // Get name value
3125
+ const name = setting.getText('value');
3126
+
3127
+ // Get data source
3128
+ const ds = this._roomListBox.dataSource.data();
3129
+
3130
+ // Check if name exists in data source
3131
+ for (let j = 0; j < ds.length; j++)
3132
+ {
3133
+ if (ds[j].name == name)
3134
+ return false;
3135
+ }
3136
+
3137
+ break;
3138
+ }
3139
+ }
3140
+
3141
+ return true;
3142
+ }
3143
+
3144
+ _enableCreateRoomPanel(enable)
3145
+ {
3146
+ let modalElement = $('#znm-createRoomModal');
3147
+
3148
+ // Enable modal close buttons
3149
+ $('button[data-dismiss="modal"]', modalElement).attr('disabled', !enable);
3150
+
3151
+ // Enable create button
3152
+ $('#znm-roomCreatorCreateBt', modalElement).attr('disabled', !enable);
3153
+
3154
+ // Enable checkbox
3155
+ $('#znm-notifyClientsCB', modalElement).attr('disabled', !enable);
3156
+
3157
+ // Enable configuration interface
3158
+ this._roomCreationIBuilder.disableInterface(!enable);
3159
+ }
3160
+
3161
+ _clearTabs(monitoredType)
3162
+ {
3163
+ // Destroy scrolling tabs
3164
+ $(`#znm-${monitoredType}TabNavigator #tabs`).scrollingTabs('destroy');
3165
+
3166
+ // Remove all tab navigator content
3167
+ this._interfaceBuilder.destroyInterface();
3168
+
3169
+ // Set all tab panels as inactive
3170
+ $(`#znm-${monitoredType}TabNavigator #tabPanels .tab-pane`).removeClass('show active');
3171
+
3172
+ // Remove tab change event listener
3173
+ $('a[data-toggle="tab"]').off('shown.bs.tab');
3174
+
3175
+ this._skipInitTabs = false;
3176
+ }
3177
+
3178
+ _showZoneTrafficData(data)
3179
+ {
3180
+ // Build user count monitor history
3181
+ if (data.containsKey('history'))
3182
+ {
3183
+ let userCountData = data.getIntArray('history');
3184
+ let samplingRateMins = data.getInt('rate');
3185
+
3186
+ this._userCountChart.addHistoryEntries(userCountData, samplingRateMins * 60);
3187
+ }
3188
+
3189
+ // Add last user count value
3190
+ this._userCountChart.addEntry(data.getInt('current'));
3191
+ }
3192
+
3193
+ _addLogEntryToGrid(grid, item)
3194
+ {
3195
+ let ds = grid.dataSource;
3196
+
3197
+ // Check items limit
3198
+ if (ds.total() == this.MAX_EXTENSION_LOG_SIZE)
3199
+ ds.remove(ds.at(0));
3200
+
3201
+ ds.add(item);
3202
+ }
3203
+
3204
+ _showUserStatsData(data)
3205
+ {
3206
+ // Packet queue filling %
3207
+ let packetQueue = Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_4__["roundToDecimals"])(data.getFloat('packet'), 2);
3208
+ this._packetQueueChart.setDataSource([{category: 'Queue', value: packetQueue}]);
3209
+
3210
+ // Dropped messages
3211
+ let droppedMsg = data.getInt('dropped');
3212
+ this._droppedMsgChart.setDataSource([{category: 'Dropped', value: droppedMsg}]);
3213
+
3214
+ // Written data amount
3215
+ let writtenDataObj = Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_4__["scaleBytes"])(data.getLong('wBytes'), 2);
3216
+ this._writtenDataChart.setDataSource([{category: 'Written', value: writtenDataObj.value, unit: writtenDataObj.unit}]);
3217
+
3218
+ // Read data amount
3219
+ let readDataObj = Object(_utils_utilities__WEBPACK_IMPORTED_MODULE_4__["scaleBytes"])(data.getLong('rBytes'), 2);
3220
+ this._readDataChart.setDataSource([{category: 'Read', value: readDataObj.value, unit: readDataObj.unit}]);
3221
+ }
3222
+
3223
+ _setGeoLocationUI(geoLocData)
3224
+ {
3225
+ const location = geoLocData.getUtfString('location');
3226
+ const error = geoLocData.getUtfString('error');
3227
+ const latitude = geoLocData.getUtfString('latitude');
3228
+ const longitude = geoLocData.getUtfString('longitude');
3229
+
3230
+ // Show location
3231
+ $('#znm-geoLocationLb').text(location);
3232
+
3233
+ // Log error
3234
+ if (error != '')
3235
+ this.shellCtrl.logMessage(error, 'warn');
3236
+
3237
+ // Enable/disable Show map button
3238
+ if (latitude != '' && longitude != '')
3239
+ {
3240
+ $('#znm-showMapBt').attr('disabled', false);
3241
+
3242
+ const url = `https://www.google.com/maps/search/?api=1&query=${Number(latitude) + ',' + Number(longitude)}`;
3243
+ $('#znm-showMapBt').attr('href', url);
3244
+ }
3245
+ }
3246
+
3247
+ _clearGeoLocationUI()
3248
+ {
3249
+ $('#znm-geoLocationLb').text('');
3250
+ $('#znm-showMapBt').attr('disabled', true);
3251
+ $('#znm-showMapBt').attr('href', '#');
3252
+ }
3253
+
3254
+ //---------------------------------
3255
+ // PRIVATE GETTERS
3256
+ //---------------------------------
3257
+
3258
+ get _activePanelType()
3259
+ {
3260
+ return this._accordion.select().data('itemType');
3261
+ }
3262
+
3263
+ get _selectedZone()
3264
+ {
3265
+ return this._zoneListBox.dataItem(this._zoneListBox.select());
3266
+ }
3267
+
3268
+ get _selectedGroup()
3269
+ {
3270
+ return this._groupsDropDown.dataItem(this._groupsDropDown.select());
3271
+ }
3272
+
3273
+ get _selectedRoom()
3274
+ {
3275
+ return this._roomListBox.dataItem(this._roomListBox.select());
3276
+ }
3277
+
3278
+ get _selectedUser()
3279
+ {
3280
+ return this._userListBox.dataItem(this._userListBox.select());
3281
+ }
3282
+
3283
+ get _isEditing()
3284
+ {
3285
+ return (this._monitoredType != null && this._monitoredName != null && this._isEditMode);
3286
+ }
3287
+ }
3288
+
3289
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
3290
+
3291
+ /***/ }),
3292
+
3293
+ /***/ "./src/utils/match-properties.js":
3294
+ /*!***************************************!*\
3295
+ !*** ./src/utils/match-properties.js ***!
3296
+ \***************************************/
3297
+ /*! exports provided: RoomPropertiesData, UserPropertiesData */
3298
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
3299
+
3300
+ "use strict";
3301
+ __webpack_require__.r(__webpack_exports__);
3302
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RoomPropertiesData", function() { return RoomPropertiesData; });
3303
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "UserPropertiesData", function() { return UserPropertiesData; });
3304
+ class RoomPropertiesData
3305
+ {
3306
+ static get LABELS() {
3307
+ let map = new Map();
3308
+
3309
+ map.set(SFS2X.RoomProperties.NAME, 'name');
3310
+ map.set(SFS2X.RoomProperties.GROUP_ID, 'groupId');
3311
+ map.set(SFS2X.RoomProperties.MAX_USERS, 'maxUsers');
3312
+ map.set(SFS2X.RoomProperties.MAX_SPECTATORS, 'maxSpectators');
3313
+ map.set(SFS2X.RoomProperties.USER_COUNT, 'userCount');
3314
+ map.set(SFS2X.RoomProperties.SPECTATOR_COUNT, 'spectatorCount');
3315
+ map.set(SFS2X.RoomProperties.IS_GAME, 'isGame');
3316
+ map.set(SFS2X.RoomProperties.IS_PRIVATE, 'isPrivate');
3317
+ map.set(SFS2X.RoomProperties.HAS_FREE_PLAYER_SLOTS, 'hasFreePlayerSlots');
3318
+ map.set(SFS2X.RoomProperties.IS_TYPE_SFSGAME, 'isSFSGameType');
3319
+
3320
+ return map;
3321
+ }
3322
+
3323
+ static getLabel(propName)
3324
+ {
3325
+ return 'Room.' + RoomPropertiesData.LABELS.get(propName);
3326
+ }
3327
+
3328
+ static get propertiesArray()
3329
+ {
3330
+ const arr = [];
3331
+
3332
+ for (const [key, value] of RoomPropertiesData.LABELS.entries())
3333
+ {
3334
+ arr.push({
3335
+ label: RoomPropertiesData.getLabel(key),
3336
+ value: key
3337
+ });
3338
+ }
3339
+
3340
+ return arr;
3341
+ }
3342
+ }
3343
+
3344
+ class UserPropertiesData
3345
+ {
3346
+ static get LABELS() {
3347
+ let map = new Map();
3348
+
3349
+ map.set(SFS2X.UserProperties.NAME, 'name');
3350
+ map.set(SFS2X.UserProperties.IS_PLAYER, 'isPlayer');
3351
+ map.set(SFS2X.UserProperties.IS_SPECTATOR, 'isSpectator');
3352
+ map.set(SFS2X.UserProperties.IS_NPC, 'isNPC');
3353
+ map.set(SFS2X.UserProperties.PRIVILEGE_ID, 'privilegeId');
3354
+
3355
+ return map;
3356
+ }
3357
+
3358
+ static getLabel(propName)
3359
+ {
3360
+ return 'User.' + UserPropertiesData.LABELS.get(propName);
3361
+ }
3362
+
3363
+ static get propertiesArray()
3364
+ {
3365
+ const arr = [];
3366
+
3367
+ for (const [key, value] of UserPropertiesData.LABELS.entries())
3368
+ {
3369
+ arr.push({
3370
+ label: UserPropertiesData.getLabel(key),
3371
+ value: key
3372
+ });
3373
+ }
3374
+
3375
+ return arr;
3376
+ }
3377
+ }
3378
+
3379
+
3380
+ /***/ })
3381
+
3382
+ }]);
3383
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtMTcuYnVuZGxlLmpzIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy9jaGFydHMvY2hhcnQtdXRpbHMuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy9jaGFydHMvdXNlci1jb3VudC1jaGFydC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL21vZHVsZS1zcGVjaWZpYy9tYXRjaC1leHByZXNzaW9uLWJ1aWxkZXIuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy9zaWRlYmFyLWxheW91dC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9tb2R1bGVzL3pvbmUtbW9uaXRvci5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy91dGlscy9tYXRjaC1wcm9wZXJ0aWVzLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Ynl0ZXNUb1NpemUsIGtCeXRlc1RvU2l6ZX0gZnJvbSAnLi4vLi4vdXRpbHMvdXRpbGl0aWVzJztcblxuZXhwb3J0IGZ1bmN0aW9uIGdldEZvcm1hdHRlZERhdGVUaW1lKGRhdGUsIGZvcm1hdCA9ICdkZCBNTU0gSEg6bW06c3MnKVxue1xuXHRyZXR1cm4ga2VuZG8udG9TdHJpbmcoZGF0ZSwgZm9ybWF0KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEJhc2ljU2hhcmVkVGVtcGxhdGUodmFsdWVGb3JtYXQgPSAnezB9Jykge1xuXHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdDxkaXYgY2xhc3M9XCJjaGFydC10b29sdGlwLWNhdGVnb3J5XCI+PHN0cm9uZz4jOiBjYXRlZ29yeSAjPC9zdHJvbmc+PC9kaXY+XG5cdFx0IyBmb3IgKHZhciBpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykgeyAjXG5cdFx0PGRpdj5cblx0XHRcdDxpIGNsYXNzPVwiZmFzIGZhLXNxdWFyZVwiIHN0eWxlPVwiY29sb3I6ICM6IHBvaW50c1tpXS5jb2xvciAjIFwiPjwvaT5cblx0XHRcdCM6IHBvaW50c1tpXS5zZXJpZXMubmFtZSMgOiAjOiBrZW5kby5mb3JtYXQoJyR7dmFsdWVGb3JtYXR9JywgcG9pbnRzW2ldLnZhbHVlKSAjXG5cdFx0PC9kaXY+XG5cdFx0IyB9ICNcblx0YCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRNZW1vcnlTaGFyZWRUZW1wbGF0ZSgpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0ZGF0YUl0ZW0uYnl0ZXNUb1NpemUgPSBieXRlc1RvU2l6ZTsgLy8gUGFzcyBieXRlc1RvU2l6ZSB1dGlsaXR5IGZ1bmN0aW9uIHRvIHRlbXBsYXRlXG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdDxkaXYgY2xhc3M9XCJjaGFydC10b29sdGlwLWNhdGVnb3J5XCI+PHN0cm9uZz4jOiBjYXRlZ29yeSAjPC9zdHJvbmc+PC9kaXY+XG5cdFx0XHQjIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7ICNcblx0XHRcdDxkaXY+XG5cdFx0XHRcdDxpIGNsYXNzPVwiZmFzIGZhLXNxdWFyZVwiIHN0eWxlPVwiY29sb3I6ICM6IHBvaW50c1tpXS5jb2xvciAjIFwiPjwvaT5cblx0XHRcdFx0IzogcG9pbnRzW2ldLnNlcmllcy5uYW1lIyA6ICM6IGJ5dGVzVG9TaXplKHBvaW50c1tpXS52YWx1ZSkgI1xuXHRcdFx0PC9kaXY+XG5cdFx0XHQjIH0gI1xuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE1lbW9yeVZhbHVlQXhpc0xhYmVsVGVtcGxhdGUoKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdGRhdGFJdGVtLmJ5dGVzVG9TaXplID0gYnl0ZXNUb1NpemU7IC8vIFBhc3MgYnl0ZXNUb1NpemUgdXRpbGl0eSBmdW5jdGlvbiB0byB0ZW1wbGF0ZVxuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQjOiBieXRlc1RvU2l6ZSh2YWx1ZSkgI1xuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ldHdvcmtTaGFyZWRUZW1wbGF0ZShjYXRlZ29yeUZvcm1hdCA9ICdkZCBNTU0gSEg6bW06c3MnKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdGRhdGFJdGVtLmtCeXRlc1RvU2l6ZSA9IGtCeXRlc1RvU2l6ZTsgLy8gUGFzcyBrQnl0ZXNUb1NpemUgdXRpbGl0eSBmdW5jdGlvbiB0byB0ZW1wbGF0ZVxuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQ8ZGl2IGNsYXNzPVwiY2hhcnQtdG9vbHRpcC1jYXRlZ29yeVwiPjxzdHJvbmc+Izoga2VuZG8udG9TdHJpbmcoY2F0ZWdvcnksICcke2NhdGVnb3J5Rm9ybWF0fScpICM8L3N0cm9uZz48L2Rpdj5cblx0XHRcdCMgZm9yICh2YXIgaSA9IDA7IGkgPCBwb2ludHMubGVuZ3RoOyBpKyspIHsgI1xuXHRcdFx0PGRpdj5cblx0XHRcdFx0PGkgY2xhc3M9XCJmYXMgZmEtc3F1YXJlXCIgc3R5bGU9XCJjb2xvcjogIzogcG9pbnRzW2ldLmNvbG9yICMgXCI+PC9pPlxuXHRcdFx0XHQjOiBwb2ludHNbaV0uc2VyaWVzLm5hbWUjIDogIzoga0J5dGVzVG9TaXplKHBvaW50c1tpXS52YWx1ZSwgMSwgJycsICcvcycpICNcblx0XHRcdDwvZGl2PlxuXHRcdFx0IyB9ICNcblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXROZXR3b3JrVmFsdWVBeGlzTGFiZWxUZW1wbGF0ZSgpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0ZGF0YUl0ZW0ua0J5dGVzVG9TaXplID0ga0J5dGVzVG9TaXplOyAvLyBQYXNzIGtCeXRlc1RvU2l6ZSB1dGlsaXR5IGZ1bmN0aW9uIHRvIHRlbXBsYXRlXG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdCM6IGtCeXRlc1RvU2l6ZSh2YWx1ZSwgMSwgJycsICcvcycpICNcblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXROZXR3b3JrVmFsdWVBeGlzTGFiZWxUZW1wbGF0ZUIoKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdGRhdGFJdGVtLmJ5dGVzVG9TaXplID0gYnl0ZXNUb1NpemU7IC8vIFBhc3MgYnl0ZXNUb1NpemUgdXRpbGl0eSBmdW5jdGlvbiB0byB0ZW1wbGF0ZVxuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQjOiBieXRlc1RvU2l6ZSh2YWx1ZSwgMSwgJycsICcvcycpICNcblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRVc2VyQ291bnRTaGFyZWRUZW1wbGF0ZShjYXRlZ29yeUZvcm1hdCA9ICdkZCBNTU0gSEg6bW06c3MnKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQ8ZGl2IGNsYXNzPVwiY2hhcnQtdG9vbHRpcC1jYXRlZ29yeVwiPjxzdHJvbmc+Izoga2VuZG8udG9TdHJpbmcoY2F0ZWdvcnksICcke2NhdGVnb3J5Rm9ybWF0fScpICM8L3N0cm9uZz48L2Rpdj5cblx0XHRcdCMgZm9yICh2YXIgaSA9IDA7IGkgPCBwb2ludHMubGVuZ3RoOyBpKyspIHsgI1xuXHRcdFx0PGRpdj5cblx0XHRcdFx0PGkgY2xhc3M9XCJmYXMgZmEtc3F1YXJlXCIgc3R5bGU9XCJjb2xvcjogIzogcG9pbnRzW2ldLmNvbG9yICMgXCI+PC9pPlxuXHRcdFx0XHQjOiBwb2ludHNbaV0uc2VyaWVzLm5hbWUjIDogIzogcG9pbnRzW2ldLnZhbHVlICNcblx0XHRcdDwvZGl2PlxuXHRcdFx0IyB9ICNcblx0XHRgKShkYXRhSXRlbSk7XG5cdH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRUaW1lUmFuZ2VUb29sdGlwVGVtcGxhdGUoKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdGRhdGFJdGVtLmdldFRvb2x0aXBTdHJpbmcgPSBmdW5jdGlvbih2MSwgdjIpIHtcblx0XHRcdGlmICh2MSA9PSB2Milcblx0XHRcdHtcblx0XHRcdFx0aWYgKHYyID09IC0yNClcblx0XHRcdFx0XHR2MiA9IC0yMztcblxuXHRcdFx0XHR2MSA9IHYyIC0gMTtcblx0XHRcdH1cblxuXHRcdFx0bGV0IHN0YXJ0ID0gTWF0aC5hYnModjEpO1xuXHRcdFx0bGV0IGVuZCA9IE1hdGguYWJzKHYyKTtcblxuXHRcdFx0cmV0dXJuIGBGcm9tICR7c3RhcnR9IGhvdXIke3N0YXJ0ICE9IDEgPyAncycgOiAnJ30gYWdvIHRvICR7ZW5kID4gMCA/ICgndG8gJyArIGVuZCArICcgaG91cicgKyAoZW5kICE9IDEgPyAncycgOiAnJykgKyAnIGFnbycpIDogJ25vdyd9YDtcblx0XHR9OyAvLyBQYXNzIHV0aWxpdHkgZnVuY3Rpb24gdG8gdGVtcGxhdGVcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0IzogZ2V0VG9vbHRpcFN0cmluZyhzZWxlY3Rpb25TdGFydCwgc2VsZWN0aW9uRW5kKSAjXG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0V1JCeXRlc0xhYmVsVGVtcGxhdGUoKSB7XG5cdHJldHVybiBmdW5jdGlvbihkYXRhSXRlbSkge1xuXHRcdHJldHVybiBrZW5kby50ZW1wbGF0ZShgXG5cdFx0XHQjOiB2YWx1ZSAjICM6IGRhdGFJdGVtLnVuaXQgI1xuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEJhc2ljVGVtcGxhdGUodmFsdWVGb3JtYXQgPSAnezB9Jykge1xuXHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdDxkaXY+XG5cdFx0XHQ8c3BhbiBjbGFzcz1cInRleHQtbm93cmFwXCI+Izoga2VuZG8udG9TdHJpbmcobmV3IERhdGUodmFsdWUueCksIFwiZGQvTU0veXkgSEg6bW1cIikgIzwvc3Bhbj5cblx0XHRcdDxicj5cblx0XHRcdDxzdHJvbmcgY2xhc3M9XCJ0ZXh0LW5vd3JhcFwiPiM6IHNlcmllcy5uYW1lICM6ICM6IGtlbmRvLmZvcm1hdCgnJHt2YWx1ZUZvcm1hdH0nLCB2YWx1ZS55KSAjIDwvc3Ryb25nPlxuXHRcdDwvZGl2PlxuXHRgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE1lbW9yeVRlbXBsYXRlKCkge1xuXHRyZXR1cm4gZnVuY3Rpb24oZGF0YUl0ZW0pIHtcblx0XHRkYXRhSXRlbS5ieXRlc1RvU2l6ZSA9IGJ5dGVzVG9TaXplOyAvLyBQYXNzIGJ5dGVzVG9TaXplIHV0aWxpdHkgZnVuY3Rpb24gdG8gdGVtcGxhdGVcblx0XHRyZXR1cm4ga2VuZG8udGVtcGxhdGUoYFxuXHRcdFx0PGRpdj5cblx0XHRcdFx0PHNwYW4gY2xhc3M9XCJ0ZXh0LW5vd3JhcFwiPiM6IGtlbmRvLnRvU3RyaW5nKG5ldyBEYXRlKHZhbHVlLngpLCBcImRkL01NL3l5IEhIOm1tXCIpICM8L3NwYW4+XG5cdFx0XHRcdDxicj5cblx0XHRcdFx0PHN0cm9uZyBjbGFzcz1cInRleHQtbm93cmFwXCI+Izogc2VyaWVzLm5hbWUgIzogIzogYnl0ZXNUb1NpemUodmFsdWUueSkgIyA8L3N0cm9uZz5cblx0XHRcdDwvZGl2PlxuXHRcdGApKGRhdGFJdGVtKTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ldHdvcmtUZW1wbGF0ZSgpIHtcblx0cmV0dXJuIGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0ZGF0YUl0ZW0uYnl0ZXNUb1NpemUgPSBieXRlc1RvU2l6ZTsgLy8gUGFzcyBieXRlc1RvU2l6ZSB1dGlsaXR5IGZ1bmN0aW9uIHRvIHRlbXBsYXRlXG5cdFx0cmV0dXJuIGtlbmRvLnRlbXBsYXRlKGBcblx0XHRcdDxkaXY+XG5cdFx0XHRcdDxzcGFuIGNsYXNzPVwidGV4dC1ub3dyYXBcIj4jOiBrZW5kby50b1N0cmluZyhuZXcgRGF0ZSh2YWx1ZS54KSwgXCJkZC9NTS95eSBISDptbVwiKSAjPC9zcGFuPlxuXHRcdFx0XHQ8YnI+XG5cdFx0XHRcdDxzdHJvbmcgY2xhc3M9XCJ0ZXh0LW5vd3JhcFwiPiM6IHNlcmllcy5uYW1lICM6ICM6IGJ5dGVzVG9TaXplKHZhbHVlLnksIDEsICcnLCAnL3MnKSAjIDwvc3Ryb25nPlxuXHRcdFx0PC9kaXY+XG5cdFx0YCkoZGF0YUl0ZW0pO1xuXHR9O1xufVxuIiwiaW1wb3J0IHtnZXRVc2VyQ291bnRTaGFyZWRUZW1wbGF0ZX0gZnJvbSAnLi9jaGFydC11dGlscyc7XG5pbXBvcnQgKiBhcyBtb21lbnQgZnJvbSAnbW9tZW50JztcblxuZXhwb3J0IGNsYXNzIFVzZXJDb3VudENoYXJ0IGV4dGVuZHMgSFRNTEVsZW1lbnRcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdCAgICBzdXBlcigpO1xuXG5cdFx0Ly8gQ3JlYXRlIGNoYXJ0IGh0bWxcblx0XHRsZXQgY2hhcnRIdG1sID0gJCgnPGRpdj4nKTtcblx0XHQkKHRoaXMpLmFwcGVuZChjaGFydEh0bWwpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBjaGFydFxuXHRcdHRoaXMuX2NoYXJ0V2lkZ2V0ID0gdGhpcy5faW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbCk7XG5cdH1cblxuXHRfaW5pdENoYXJ0V2lkZ2V0KGNoYXJ0SHRtbClcblx0e1xuXHRcdHJldHVybiBjaGFydEh0bWwua2VuZG9DaGFydCh7XG5cdFx0XHR0cmFuc2l0aW9uczogZmFsc2UsXG5cdFx0XHRjaGFydEFyZWE6IHtcblx0XHRcdFx0aGVpZ2h0OiAyNzAsXG5cdFx0XHRcdGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCdcblx0XHRcdH0sXG5cdCAgICAgICAgbGVnZW5kOiB7XG5cdCAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXNEZWZhdWx0czoge1xuXHQgICAgICAgICAgICB0eXBlOiAnYXJlYScsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nLFxuXHQgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJ3RyYW5zcGFyZW50J1xuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbe1xuXHRcdFx0XHRuYW1lOiAnVXNlcnMnLFxuXHQgICAgICAgICAgICBmaWVsZDogJ3VzZXJzJyxcblx0ICAgICAgICAgICAgY2F0ZWdvcnlGaWVsZDogJ3RpbWUnLFxuXHRcdFx0XHRjb2xvcjogJyNmZDdkMjQnLFxuXHRcdFx0XHRsaW5lOiB7XG5cdFx0XHRcdFx0d2lkdGg6IDJcblx0XHRcdFx0fVxuXHQgICAgICAgIH1dLFxuXHQgICAgICAgIHZhbHVlQXhpczoge1xuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICAgIGxpbmU6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1pbjogMCxcblx0ICAgICAgICB9LFxuXHQgICAgICAgIGNhdGVnb3J5QXhpczoge1xuXHRcdFx0XHRtYWpvckdyaWRMaW5lczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogdHJ1ZSxcblx0XHRcdFx0XHRzdGVwOiA2MFxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtYWpvclRpY2tzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogdHJ1ZSxcblx0XHRcdFx0XHRzdGVwOiA2MFxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsYWJlbHM6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHRcdHN0ZXA6IDYwXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGJhc2VVbml0OiAnbWludXRlcycsXG5cdFx0XHRcdHR5cGU6ICdkYXRlJyxcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHRvb2x0aXA6IHtcblx0XHRcdFx0c2hhcmVkOiB0cnVlLFxuXHQgICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuXHRcdFx0XHRzaGFyZWRUZW1wbGF0ZTogZ2V0VXNlckNvdW50U2hhcmVkVGVtcGxhdGUoJ2RkIE1NTSBISDptbScpLFxuXHRcdFx0XHRiYWNrZ3JvdW5kOiAnI2U0ZTRlNCdcblx0ICAgICAgICB9XG5cdCAgICB9KS5kYXRhKCdrZW5kb0NoYXJ0Jyk7XG5cdH1cblxuXHRyZWRyYXcoKVxuXHR7XG5cdFx0dGhpcy5fY2hhcnRXaWRnZXQucmVkcmF3KCk7XG5cdH1cblxuXHRzZXQgcmFuZ2UodmFsdWVzKVxuXHR7XG5cdFx0dGhpcy5fcmFuZ2UgPSB2YWx1ZXM7XG5cblx0XHR0aGlzLl91cGRhdGVYQXhpc0xpbWl0cygpO1xuXHR9XG5cblx0Z2V0IHJhbmdlKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9yYW5nZTtcblx0fVxuXG5cdGFkZEhpc3RvcnlFbnRyaWVzKHVzZXJDb3VudERhdGEsIHNhbXBsaW5nUmF0ZVNlY29uZHMpXG5cdHtcblx0XHRsZXQgZGF0ZSA9IG5ldyBEYXRlKCk7XG5cdFx0bGV0IHN0YXJ0ID0gbW9tZW50KGRhdGUpO1xuXHRcdHN0YXJ0LnN1YnRyYWN0KChzYW1wbGluZ1JhdGVTZWNvbmRzICogdXNlckNvdW50RGF0YS5sZW5ndGgpLCAncycpXG5cblx0XHRsZXQgZGF0YVNvdXJjZSA9IG5ldyBrZW5kby5kYXRhLkRhdGFTb3VyY2UoKTtcblxuXHRcdGZvciAobGV0IGkgPSAxOyBpIDwgdXNlckNvdW50RGF0YS5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHRsZXQgZGF0ZSA9IHN0YXJ0LmNsb25lKCk7XG5cdFx0XHRkYXRlLmFkZChpICogc2FtcGxpbmdSYXRlU2Vjb25kcywgJ3MnKTtcblxuXHRcdFx0dGhpcy5hZGRFbnRyeSh1c2VyQ291bnREYXRhW2ldLCBkYXRhU291cmNlLCBkYXRlLnRvRGF0ZSgpLCBmYWxzZSk7XG5cdFx0fVxuXG5cdFx0Ly8gQXNzaWduIGRhdGFzb3VyY2UgdG8gY2hhcnRcblx0XHR0aGlzLl9jaGFydFdpZGdldC5zZXREYXRhU291cmNlKGRhdGFTb3VyY2UpO1xuXG5cdFx0Ly8gVXBkYXRlIGF4aXNcblx0XHR0aGlzLl91cGRhdGVYQXhpc0xpbWl0cygpO1xuXHR9XG5cblx0YWRkRW50cnkodXNlckNvdW50LCBkYXRhU291cmNlID0gbnVsbCwgZGF0ZSA9IG51bGwsIHVwZGF0ZUF4aXMgPSB0cnVlKVxuXHR7XG5cdFx0aWYgKGRhdGUgPT0gbnVsbClcblx0XHRcdGRhdGUgPSBuZXcgRGF0ZSgpO1xuXG5cdFx0bGV0IG5ld0VudHJ5ID0ge1xuXHRcdFx0dGltZTogZGF0ZSxcblx0XHRcdHVzZXJzOiB1c2VyQ291bnRcblx0XHR9O1xuXG5cdFx0Ly8gQWRkIGVudHJ5IHRvIGRhdGEgc291cmNlXG5cdFx0aWYgKGRhdGFTb3VyY2UgPT0gbnVsbClcblx0XHRcdGRhdGFTb3VyY2UgPSB0aGlzLl9kYXRhU291cmNlO1xuXG5cdFx0ZGF0YVNvdXJjZS5hZGQobmV3RW50cnkpO1xuXG5cdFx0aWYgKHVwZGF0ZUF4aXMpXG5cdFx0XHR0aGlzLl91cGRhdGVYQXhpc0xpbWl0cygpO1xuXHR9XG5cblx0X3VwZGF0ZVhBeGlzTGltaXRzKClcblx0e1xuXHRcdGxldCBkcyA9IHRoaXMuX2RhdGFTb3VyY2U7XG5cblx0XHRpZiAoZHMudG90YWwoKSA+IDApXG5cdFx0e1xuXHRcdFx0Y29uc3QgY2hhcnRNaW5pbXVtID0gbW9tZW50KHRoaXMuX2xhc3REYXRlKS5hZGQodGhpcy5fcmFuZ2VbMF0sICdoJyk7XG5cdFx0XHRjb25zdCBjaGFydE1heGltdW0gPSBtb21lbnQodGhpcy5fbGFzdERhdGUpLmFkZCh0aGlzLl9yYW5nZVsxXSwgJ2gnKTtcblxuXHRcdFx0dGhpcy5fY2hhcnRXaWRnZXQub3B0aW9ucy5jYXRlZ29yeUF4aXMubWluID0gY2hhcnRNaW5pbXVtLnRvRGF0ZSgpO1xuXHRcdFx0dGhpcy5fY2hhcnRXaWRnZXQub3B0aW9ucy5jYXRlZ29yeUF4aXMubWF4ID0gY2hhcnRNYXhpbXVtLnRvRGF0ZSgpO1xuXG5cdFx0XHR0aGlzLl9jaGFydFdpZGdldC5yZWRyYXcoKTtcblx0XHR9XG5cdH1cblxuXHRnZXQgX2RhdGFTb3VyY2UoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2NoYXJ0V2lkZ2V0LmRhdGFTb3VyY2U7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCd1c2VyLWNvdW50LWNoYXJ0JykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ3VzZXItY291bnQtY2hhcnQnLCBVc2VyQ291bnRDaGFydCk7XG4iLCJleHBvcnQgY2xhc3MgTWF0Y2hFeHByZXNzaW9uQnVpbGRlciBleHRlbmRzIEhUTUxFbGVtZW50XG57XG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHQgICAgc3VwZXIoKTtcblxuXHRcdHRoaXMuRVhQUkVTU0lPTl9VUERBVEVEX0VWRU5UID0gJ2V4cHJlc3Npb25VcGRhdGVkJztcblxuXHRcdHRoaXMuX2RpYWxvZyA9ICQoYFxuXHRcdFx0PGRpdiBjbGFzcz1cIm1vZGFsXCIgaWQ9XCJtYXRjaEV4cHJCdWlsZGVyTW9kYWxcIiB0YWJpbmRleD1cIi0xXCIgcm9sZT1cImRpYWxvZ1wiIGFyaWEtbGFiZWxsZWRieT1cIm1hdGNoRXhwckJ1aWxkZXJNb2RhbFRpdGxlXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+XG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1kaWFsb2cgbW9kYWwtZGlhbG9nLWNlbnRlcmVkIG1vZGFsLWxnXCIgcm9sZT1cImRvY3VtZW50XCI+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cIm1vZGFsLWNvbnRlbnRcIj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1oZWFkZXJcIj5cblx0XHRcdFx0XHRcdFx0PGg1IGNsYXNzPVwibW9kYWwtdGl0bGUgdGV4dC1wcmltYXJ5XCIgaWQ9XCJtYXRjaEV4cHJCdWlsZGVyTW9kYWxUaXRsZVwiPi4uLjwvaDU+XG5cdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1ib2R5IHAtMFwiPlxuXHRcdFx0XHRcdFx0XHQ8Zm9ybSBjbGFzcz1cImJnLWNvbG9yLWRlZmF1bHQgcC0zXCI+XG5cdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImQtaW5saW5lLWZsZXggYWxpZ24taXRlbXMtY2VudGVyIHJhZGlvLWJ1dHRvbi1ncm91cCBpbmxpbmUtZm9ybS1ncm91cHNcIj5cblx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjdXN0b20tY29udHJvbCBjdXN0b20tcmFkaW8gY3VzdG9tLWNvbnRyb2wtaW5saW5lIG1yLTJcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGlucHV0IHR5cGU9XCJyYWRpb1wiIGlkPVwiYW5kT3BlcmF0b3JSQlwiIG5hbWU9XCJvcGVyYXRvclJCR1wiIGNsYXNzPVwiY3VzdG9tLWNvbnRyb2wtaW5wdXRcIiB2YWx1ZT1cIkFORFwiIGNoZWNrZWQgZGlzYWJsZWQ+XG5cdFx0XHRcdFx0XHRcdFx0XHRcdDxsYWJlbCBjbGFzcz1cImN1c3RvbS1jb250cm9sLWxhYmVsXCIgZm9yPVwiYW5kT3BlcmF0b3JSQlwiPkFORDwvbGFiZWw+XG5cdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjdXN0b20tY29udHJvbCBjdXN0b20tcmFkaW8gY3VzdG9tLWNvbnRyb2wtaW5saW5lIG1yLTJcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGlucHV0IHR5cGU9XCJyYWRpb1wiIGlkPVwib3JPcGVyYXRvclJCXCIgbmFtZT1cIm9wZXJhdG9yUkJHXCIgY2xhc3M9XCJjdXN0b20tY29udHJvbC1pbnB1dFwiIHZhbHVlPVwiT1JcIiBkaXNhYmxlZD5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGxhYmVsIGNsYXNzPVwiY3VzdG9tLWNvbnRyb2wtbGFiZWxcIiBmb3I9XCJvck9wZXJhdG9yUkJcIj5PUjwvbGFiZWw+XG5cdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiZC1pbmxpbmUtYmxvY2tcIj5cblx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJpbmxpbmUtZm9ybS1ncm91cHMgbXktMVwiPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHQ8aW5wdXQgaWQ9XCJ2YXJOYW1lQ0JcIi8+XG5cdFx0XHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJpbmxpbmUtZm9ybS1ncm91cHMgbXktMVwiPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHQ8aW5wdXQgaWQ9XCJ0eXBlRERcIiBjbGFzcz1cIm1hdGNoVHlwZURyb3Bkb3duXCIvPlxuXHRcdFx0XHRcdFx0XHRcdFx0XHQ8aW5wdXQgaWQ9XCJjb25kaXRpb25ERFwiIGNsYXNzPVwibWF0Y2hDb25kaXRpb25Ecm9wZG93blwiLz5cblx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJkLWlubGluZSBpbmxpbmUtZm9ybS1ncm91cHNcIj5cblx0XHRcdFx0XHRcdFx0XHRcdDxpbnB1dCBpZD1cInZhbHVlSW5cIiBjbGFzcz1cImstdGV4dGJveCBtdC0xXCIgcGxhY2Vob2xkZXI9XCJWYWx1ZVwiLz5cblx0XHRcdFx0XHRcdFx0XHRcdDxidXR0b24gaWQ9XCJtYXRjaEV4cHJBZGRCdFwiIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImstYnV0dG9uIGstc2Vjb25kYXJ5IG10LTFcIj48aSBjbGFzcz1cImZhcyBmYS1wbHVzIG1yLTFcIj48L2k+QWRkPC9idXR0b24+XG5cdFx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdDwvZm9ybT5cblxuXHRcdFx0XHRcdFx0XHQ8ZGl2IGlkPVwibWF0Y2hFeHByR3JpZFwiIGNsYXNzPVwibS0zXCI+PC9kaXY+XG5cdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXIgZC1mbGV4XCI+XG5cdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJmbGV4LWdyb3ctMSB0ZXh0LWxlZnRcIj5cblx0XHRcdFx0XHRcdFx0XHQ8YnV0dG9uIGlkPVwibWF0Y2hFeHByQXBwbHlCdFwiIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImstYnV0dG9uIGstcHJpbWFyeSBtci0yXCI+PGkgY2xhc3M9XCJmYXMgZmEtY2hlY2stY2lyY2xlIG1yLTFcIj48L2k+QXBwbHk8L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJmbGV4LWdyb3ctMSB0ZXh0LXJpZ2h0XCI+XG5cdFx0XHRcdFx0XHRcdFx0PGJ1dHRvbiBpZD1cIm1hdGNoRXhwclJlbW92ZUJ0XCIgdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiay1idXR0b24gay1zZWNvbmRhcnlcIiBkaXNhYmxlZD48aSBjbGFzcz1cImZhcyBmYS1taW51cy1jaXJjbGUgbXItMVwiPjwvaT5SZW1vdmUgc2VsZWN0ZWQ8L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0XHQ8YnV0dG9uIGlkPVwibWF0Y2hFeHByQ2xlYXJCdFwiIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImstYnV0dG9uIGstc2Vjb25kYXJ5XCI+PGkgY2xhc3M9XCJmYXMgZmEtdGltZXMtY2lyY2xlIG1yLTFcIj48L2k+Q2xlYXIgYWxsPC9idXR0b24+XG5cdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdDwvZGl2PlxuXHRcdFx0PC9kaXY+XG5cdFx0YCk7XG5cblx0XHQkKCcjbWF0Y2hFeHByQWRkQnQnLCB0aGlzLl9kaWFsb2cpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25BZGRCdENsaWNrLCB0aGlzKSk7XG5cdFx0JCgnI21hdGNoRXhwckFwcGx5QnQnLCB0aGlzLl9kaWFsb2cpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25BcHBseUJ0Q2xpY2ssIHRoaXMpKTtcblx0XHQkKCcjbWF0Y2hFeHByUmVtb3ZlQnQnLCB0aGlzLl9kaWFsb2cpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25SZW1vdmVCdENsaWNrLCB0aGlzKSk7XG5cdFx0JCgnI21hdGNoRXhwckNsZWFyQnQnLCB0aGlzLl9kaWFsb2cpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25DbGVhckJ0Q2xpY2ssIHRoaXMpKTtcblxuXHRcdC8vIElOSVRJQUxJWkUgRk9STSBJVEVNU1xuXG5cdFx0dGhpcy5fdmFyTmFtZUNiID0gJCgnI3Zhck5hbWVDQicsIHRoaXMuX2RpYWxvZykua2VuZG9Db21ib0JveCh7XG5cdFx0XHRkYXRhVGV4dEZpZWxkOiAnbGFiZWwnLFxuXHRcdFx0ZGF0YVZhbHVlRmllbGQ6ICd2YWx1ZScsXG5cdFx0XHRwbGFjZWhvbGRlcjogJ1ZhcmlhYmxlIG5hbWUnLFxuXHRcdH0pLmRhdGEoJ2tlbmRvQ29tYm9Cb3gnKTtcblxuXHRcdC8vIFNldCB0eXBlcyBkcm9wZG93biBkYXRhIHNvdXJjZVxuXHRcdC8vIE5PVEU6IGluIG9yZGVyIHRvIGF2b2lkIFh4eE1hdGNoIG9iamVjdHMgdG8gYmUgd3JhcHBlZCBieSBLZW5kbyBkYXRhIHNvdXJjZSwgd2UgaGF2ZSB0byBwYXNzIHRoZW0gdXNpbmcgXyBwcm9wZXJ0eSBuYW1lc1xuXHRcdGxldCB0eXBlRFMgPSBbXTtcblxuXHRcdC8vIEJvb2xlYW4gLS0tLS0tLS0tLS0tLS0tLVxuXHRcdHR5cGVEUy5wdXNoKHtcblx0XHRcdGxhYmVsOiAnQm9vbGVhbicsXG5cdFx0XHRfdmFsdWU6IFNGUzJYLkJvb2xNYXRjaC5FUVVBTFMsXG5cdFx0XHRjb25kaXRpb25zOiBbXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsYWJlbDogU0ZTMlguQm9vbE1hdGNoLkVRVUFMUy5zeW1ib2wsXG5cdFx0XHRcdFx0X3ZhbHVlOiBTRlMyWC5Cb29sTWF0Y2guRVFVQUxTLFxuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0bGFiZWw6IFNGUzJYLkJvb2xNYXRjaC5OT1RfRVFVQUxTLnN5bWJvbCxcblx0XHRcdFx0XHRfdmFsdWU6IFNGUzJYLkJvb2xNYXRjaC5OT1RfRVFVQUxTLFxuXHRcdFx0XHR9XG5cdFx0XHRdXG5cdFx0fSk7XG5cblx0XHQvLyBOdW1iZXIgLS0tLS0tLS0tLS0tLS0tLVxuXHRcdHR5cGVEUy5wdXNoKHtcblx0XHRcdGxhYmVsOiAnTnVtYmVyJyxcblx0XHRcdF92YWx1ZTogU0ZTMlguTnVtYmVyTWF0Y2guRVFVQUxTLFxuXHRcdFx0Y29uZGl0aW9uczogW1xuXHRcdFx0XHR7XG5cdFx0XHRcdFx0bGFiZWw6IFNGUzJYLk51bWJlck1hdGNoLkVRVUFMUy5zeW1ib2wsXG5cdFx0XHRcdFx0X3ZhbHVlOiBTRlMyWC5OdW1iZXJNYXRjaC5FUVVBTFMsXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsYWJlbDogU0ZTMlguTnVtYmVyTWF0Y2guTk9UX0VRVUFMUy5zeW1ib2wsXG5cdFx0XHRcdFx0X3ZhbHVlOiBTRlMyWC5OdW1iZXJNYXRjaC5OT1RfRVFVQUxTLFxuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0bGFiZWw6IFNGUzJYLk51bWJlck1hdGNoLkdSRUFURVJfVEhBTi5zeW1ib2wsXG5cdFx0XHRcdFx0X3ZhbHVlOiBTRlMyWC5OdW1iZXJNYXRjaC5HUkVBVEVSX1RIQU4sXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsYWJlbDogU0ZTMlguTnVtYmVyTWF0Y2guTEVTU19USEFOLnN5bWJvbCxcblx0XHRcdFx0XHRfdmFsdWU6IFNGUzJYLk51bWJlck1hdGNoLkxFU1NfVEhBTixcblx0XHRcdFx0fSxcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGxhYmVsOiBTRlMyWC5OdW1iZXJNYXRjaC5HUkVBVEVSX1RIQU5fT1JfRVFVQUxfVE8uc3ltYm9sLFxuXHRcdFx0XHRcdF92YWx1ZTogU0ZTMlguTnVtYmVyTWF0Y2guR1JFQVRFUl9USEFOX09SX0VRVUFMX1RPLFxuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0bGFiZWw6IFNGUzJYLk51bWJlck1hdGNoLkxFU1NfVEhBTl9PUl9FUVVBTF9UTy5zeW1ib2wsXG5cdFx0XHRcdFx0X3ZhbHVlOiBTRlMyWC5OdW1iZXJNYXRjaC5MRVNTX1RIQU5fT1JfRVFVQUxfVE8sXG5cdFx0XHRcdH1cblx0XHRcdF1cblx0XHR9KTtcblxuXHRcdC8vIFN0cmluZyAtLS0tLS0tLS0tLS0tLS0tXG5cdFx0dHlwZURTLnB1c2goe1xuXHRcdFx0bGFiZWw6ICdTdHJpbmcnLFxuXHRcdFx0X3ZhbHVlOiBTRlMyWC5TdHJpbmdNYXRjaC5FUVVBTFMsXG5cdFx0XHRjb25kaXRpb25zOiBbXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsYWJlbDogU0ZTMlguU3RyaW5nTWF0Y2guRVFVQUxTLnN5bWJvbCxcblx0XHRcdFx0XHRfdmFsdWU6IFNGUzJYLlN0cmluZ01hdGNoLkVRVUFMUyxcblx0XHRcdFx0fSxcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGxhYmVsOiBTRlMyWC5TdHJpbmdNYXRjaC5OT1RfRVFVQUxTLnN5bWJvbCxcblx0XHRcdFx0XHRfdmFsdWU6IFNGUzJYLlN0cmluZ01hdGNoLk5PVF9FUVVBTFMsXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsYWJlbDogU0ZTMlguU3RyaW5nTWF0Y2guQ09OVEFJTlMuc3ltYm9sLFxuXHRcdFx0XHRcdF92YWx1ZTogU0ZTMlguU3RyaW5nTWF0Y2guQ09OVEFJTlMsXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsYWJlbDogU0ZTMlguU3RyaW5nTWF0Y2guU1RBUlRTX1dJVEguc3ltYm9sLFxuXHRcdFx0XHRcdF92YWx1ZTogU0ZTMlguU3RyaW5nTWF0Y2guU1RBUlRTX1dJVEgsXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsYWJlbDogU0ZTMlguU3RyaW5nTWF0Y2guRU5EU19XSVRILnN5bWJvbCxcblx0XHRcdFx0XHRfdmFsdWU6IFNGUzJYLlN0cmluZ01hdGNoLkVORFNfV0lUSCxcblx0XHRcdFx0fVxuXHRcdFx0XVxuXHRcdH0pO1xuXG5cdFx0dGhpcy5fdHlwZURkID0gJCgnI3R5cGVERCcsIHRoaXMuX2RpYWxvZykua2VuZG9Ecm9wRG93bkxpc3Qoe1xuXHRcdFx0ZGF0YVNvdXJjZTogdHlwZURTLFxuXHRcdFx0ZGF0YVRleHRGaWVsZDogJ2xhYmVsJyxcblx0XHRcdGRhdGFWYWx1ZUZpZWxkOiAnX3ZhbHVlJyxcblx0XHRcdG9wdGlvbkxhYmVsOiB7XG5cdFx0XHRcdGxhYmVsOiAnVHlwZScsXG5cdFx0XHRcdF92YWx1ZTogJydcblx0XHRcdH0sXG5cdFx0XHRvcHRpb25MYWJlbFRlbXBsYXRlOiAnPHNwYW4gY2xhc3M9XCJ0ZXh0LW11dGVkXCI+IzpsYWJlbCM8L3NwYW4+Jyxcblx0XHRcdGNoYW5nZTogJC5wcm94eShmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKHRoaXMuX3R5cGVEZCAmJiB0aGlzLl90eXBlRGQuc2VsZWN0KCkpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsZXQgc2VsZWN0ZWRUeXBlID0gdGhpcy5fdHlwZURkLmRhdGFJdGVtKHRoaXMuX3R5cGVEZC5zZWxlY3QoKSk7XG5cdFx0XHRcdFx0dGhpcy5fY29uZGl0aW9uRGQuc2V0RGF0YVNvdXJjZShzZWxlY3RlZFR5cGUuY29uZGl0aW9ucyk7XG5cdFx0XHRcdFx0dGhpcy5fY29uZGl0aW9uRGQuc2VsZWN0KDEpO1xuXHRcdFx0XHR9XG5cdFx0XHR9LCB0aGlzKVxuXHRcdH0pLmRhdGEoJ2tlbmRvRHJvcERvd25MaXN0Jyk7XG5cblx0XHR0aGlzLl9jb25kaXRpb25EZCA9ICQoJyNjb25kaXRpb25ERCcsIHRoaXMuX2RpYWxvZykua2VuZG9Ecm9wRG93bkxpc3Qoe1xuXHRcdFx0ZGF0YVRleHRGaWVsZDogJ2xhYmVsJyxcblx0XHRcdGRhdGFWYWx1ZUZpZWxkOiAnX3ZhbHVlJyxcblx0XHRcdG9wdGlvbkxhYmVsOiB7XG5cdFx0XHRcdGxhYmVsOiAnQ29uZGl0aW9uJyxcblx0XHRcdFx0X3ZhbHVlOiAnJ1xuXHRcdFx0fSxcblx0XHRcdG9wdGlvbkxhYmVsVGVtcGxhdGU6ICc8c3BhbiBjbGFzcz1cInRleHQtbXV0ZWRcIj4jOmxhYmVsIzwvc3Bhbj4nLFxuXHRcdH0pLmRhdGEoJ2tlbmRvRHJvcERvd25MaXN0Jyk7XG5cblx0XHR0aGlzLl92YWx1ZUluID0gJCgnI3ZhbHVlSW4nLCB0aGlzLl9kaWFsb2cpO1xuXG5cdFx0Ly8gSU5JVElBTElaRSBHUklEXG5cblx0XHR0aGlzLl9ncmlkID0gJCgnI21hdGNoRXhwckdyaWQnLCB0aGlzLl9kaWFsb2cpLmtlbmRvR3JpZCh7XG5cdFx0XHRkYXRhU291cmNlOiBbXSxcblx0XHRcdHJlc2l6YWJsZTogdHJ1ZSxcblx0XHRcdHNlbGVjdGFibGU6ICdyb3cnLFxuXHRcdFx0Y2hhbmdlOiAkLnByb3h5KHRoaXMuX29uR3JpZFNlbGVjdGlvbkNoYW5nZSwgdGhpcyksXG5cdFx0XHRub1JlY29yZHM6IHtcblx0XHRcdFx0dGVtcGxhdGU6ICdObyBlbnRyaWVzLidcblx0XHRcdH0sXG5cdFx0XHRjb2x1bW5zOiBbXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRmaWVsZDogJ29wZXJhdG9yJyxcblx0XHRcdFx0XHR0aXRsZTogJ09wZXJhdG9yJyxcblx0XHRcdFx0XHR3aWR0aDogOTBcblx0XHRcdFx0fSxcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGZpZWxkOiAnbGFiZWwnLFxuXHRcdFx0XHRcdHRpdGxlOiAnTmFtZScsXG5cdFx0XHRcdFx0d2lkdGg6IDEyMFxuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0ZmllbGQ6ICd0eXBlTGFiZWwnLFxuXHRcdFx0XHRcdHRpdGxlOiAnVHlwZScsXG5cdFx0XHRcdFx0d2lkdGg6IDg1XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRmaWVsZDogJ3N5bWJvbCcsXG5cdFx0XHRcdFx0dGl0bGU6ICdDb25kaXRpb24nLFxuXHRcdFx0XHRcdHdpZHRoOiA5NVxuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0ZmllbGQ6ICd2YWx1ZScsXG5cdFx0XHRcdFx0dGl0bGU6ICdWYWx1ZScsXG5cdFx0XHRcdFx0d2lkdGg6IDIwMFxuXHRcdFx0XHR9LFxuXHRcdFx0XVxuXHRcdH0pLmRhdGEoJ2tlbmRvR3JpZCcpO1xuXHR9XG5cblx0Z2V0IHRpdGxlKClcblx0e1xuXHRcdHJldHVybiAkKCcjbWF0Y2hFeHByQnVpbGRlck1vZGFsVGl0bGUnLCB0aGlzLl9kaWFsb2cpLnRleHQoKTtcblx0fVxuXG5cdHNldCB0aXRsZSh2YWx1ZSlcblx0e1xuXHRcdCQoJyNtYXRjaEV4cHJCdWlsZGVyTW9kYWxUaXRsZScsIHRoaXMuX2RpYWxvZykudGV4dCh2YWx1ZSk7XG5cdH1cblxuXHRnZXQgcHJlZGVmaW5lZFZhck5hbWVzKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9wcmVkZWZpbmVkVmFyTmFtZXM7XG5cdH1cblxuXHRzZXQgcHJlZGVmaW5lZFZhck5hbWVzKHZhbHVlKVxuXHR7XG5cdFx0dGhpcy5fcHJlZGVmaW5lZFZhck5hbWVzID0gdmFsdWU7XG5cblx0XHR0aGlzLl92YXJOYW1lQ2Iuc2V0RGF0YVNvdXJjZSh2YWx1ZSk7XG5cdH1cblxuXHRnZXQgZmlsdGVyRXhwcmVzc2lvbigpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fZmlsdGVyRXhwcmVzc2lvbjtcblx0fVxuXG5cdHNob3coKVxuXHR7XG5cdFx0dGhpcy5fZGlhbG9nLm1vZGFsKHtcblx0XHRcdGJhY2tkcm9wOiAnc3RhdGljJyxcblx0XHRcdGtleWJvYXJkOiBmYWxzZSxcblx0XHRcdHNob3c6IHRydWVcblx0XHR9KTtcblx0fVxuXG5cdF9vbkdyaWRTZWxlY3Rpb25DaGFuZ2UoKVxuXHR7XG5cdFx0bGV0IHNlbGVjdGVkUm93cyA9IHRoaXMuX2dyaWQuc2VsZWN0KCk7XG5cdFx0bGV0IHNlbGVjdGVkRGF0YUl0ZW1zID0gW107XG5cblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHNlbGVjdGVkUm93cy5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHRsZXQgZGF0YUl0ZW0gPSB0aGlzLl9ncmlkLmRhdGFJdGVtKHNlbGVjdGVkUm93c1tpXSk7XG5cdFx0XHRzZWxlY3RlZERhdGFJdGVtcy5wdXNoKGRhdGFJdGVtKTtcblx0XHR9XG5cblx0XHQvLyBFbmFibGUvZGlzYWJsZSByZW1vdmUgYnV0dG9uXG5cdFx0JCgnI21hdGNoRXhwclJlbW92ZUJ0JywgdGhpcy5fZGlhbG9nKS5hdHRyKCdkaXNhYmxlZCcsIHNlbGVjdGVkRGF0YUl0ZW1zLmxlbmd0aCA9PSAwKTtcblx0fVxuXG5cdF9vbkFkZEJ0Q2xpY2soKVxuXHR7XG5cdFx0aWYgKHRoaXMuX3Zhck5hbWVDYi52YWx1ZSgpICE9ICcnICYmIHRoaXMuX3R5cGVEZC5zZWxlY3QoKSlcblx0XHR7XG5cdFx0XHQvLyBWYXJpYWJsZSBuYW1lIGFuZCBsYWJlbFxuXHRcdFx0bGV0IHZhck5hbWUsIHZhckxhYmVsO1xuXG5cdFx0XHRpZiAodGhpcy5fdmFyTmFtZUNiLnNlbGVjdCgpID4gLTEpXG5cdFx0XHR7XG5cdFx0XHRcdGxldCBkYXRhSXRlbSA9IHRoaXMuX3Zhck5hbWVDYi5kYXRhSXRlbSh0aGlzLl92YXJOYW1lQ2Iuc2VsZWN0KCkpO1xuXHRcdFx0XHR2YXJOYW1lID0gZGF0YUl0ZW0udmFsdWU7XG5cdFx0XHRcdHZhckxhYmVsID0gZGF0YUl0ZW0ubGFiZWw7XG5cdFx0XHR9XG5cdFx0XHRlbHNlXG5cdFx0XHRcdHZhck5hbWUgPSB2YXJMYWJlbCA9IHRoaXMuX3Zhck5hbWVDYi52YWx1ZSgpO1xuXG5cdFx0XHQvLyBWYXJpYWJsZSB0eXBlJ3MgbGFiZWxcblx0XHRcdGxldCB0eXBlTGFiZWwgPSB0aGlzLl90eXBlRGQuZGF0YUl0ZW0odGhpcy5fdHlwZURkLnNlbGVjdCgpKS5sYWJlbDtcblxuXHRcdFx0Ly8gTWF0Y2ggY29uZGl0aW9uXG5cdFx0XHRsZXQgY29uZGl0aW9uID0gdGhpcy5fY29uZGl0aW9uRGQuZGF0YUl0ZW0odGhpcy5fY29uZGl0aW9uRGQuc2VsZWN0KCkpLl92YWx1ZTtcblxuXHRcdFx0Ly8gRXhwcmVzc2lvbiBvcGVyYXRvclxuXHRcdFx0bGV0IG9wZXJhdG9yID0gdGhpcy5fZ3JpZC5kYXRhU291cmNlLnRvdGFsKCkgPiAwID8gJCgnaW5wdXRbbmFtZT1vcGVyYXRvclJCR106Y2hlY2tlZCcsIHRoaXMuX2RpYWxvZykudmFsKCkgOiBudWxsO1xuXG5cdFx0XHQvLyBWYXJpYWJsZSB2YWx1ZVxuXHRcdFx0bGV0IHZhbCA9IHRoaXMuX3ZhbHVlSW4udmFsKCk7XG5cdFx0XHRsZXQgdmFyVmFsdWU7XG5cblx0XHRcdGlmIChjb25kaXRpb24gaW5zdGFuY2VvZiBTRlMyWC5Cb29sTWF0Y2gpXG5cdFx0XHRcdHZhclZhbHVlID0gKHZhbCA9PSAndHJ1ZScgPyB0cnVlIDogZmFsc2UpO1xuXHRcdFx0ZWxzZSBpZiAoY29uZGl0aW9uIGluc3RhbmNlb2YgU0ZTMlguTnVtYmVyTWF0Y2gpXG5cdFx0XHRcdHZhclZhbHVlID0gKGlzTmFOKE51bWJlcih2YWwpKSA/IDAgOiBOdW1iZXIodmFsKSk7XG5cdFx0XHRlbHNlXG5cdFx0XHRcdHZhclZhbHVlID0gdmFsO1xuXG5cdFx0XHQvLyBBZGQgaXRlbSB0byBncmlkXG5cdFx0XHRsZXQgZXhwclBhcnQgPSB0aGlzLl9nZXRFeHByZXNzaW9uUGFydCh2YXJMYWJlbCwgdmFyTmFtZSwgdmFyVmFsdWUsIHR5cGVMYWJlbCwgY29uZGl0aW9uLCBvcGVyYXRvcik7XG5cdFx0XHR0aGlzLl9ncmlkLmRhdGFTb3VyY2UuYWRkKGV4cHJQYXJ0KTtcblxuXHRcdFx0Ly8gUmVzZXQgaW5wdXRzXG5cdFx0XHR0aGlzLl92YXJOYW1lQ2IudmFsdWUoJycpO1xuXHRcdFx0dGhpcy5fdmFsdWVJbi52YWwoJycpO1xuXG5cdFx0XHQvLyBFbmFibGUgb3BlcmF0b3IgcmFkaW8gYnV0dG9uc1xuXHRcdFx0dGhpcy5fZW5hYmxlT3BlcmF0b3JSYih0cnVlKTtcblx0XHR9XG5cdH1cblxuXHRfb25BcHBseUJ0Q2xpY2soKVxuXHR7XG5cdFx0Ly8gSGlkZSBkaWFsb2dcblx0XHR0aGlzLl9kaWFsb2cubW9kYWwoJ2hpZGUnKTtcblxuXHRcdC8vIENsZWFyIGdyaWQgc2VsZWN0aW9uXG5cdFx0dGhpcy5fZ3JpZC5jbGVhclNlbGVjdGlvbigpO1xuXG5cdFx0Ly8gQnVpbGQgZmluYWwgbWF0Y2ggZXhwcmVzc2lvblxuXHRcdHRoaXMuX2ZpbHRlckV4cHJlc3Npb24gPSBudWxsO1xuXG5cdFx0aWYgKHRoaXMuX2dyaWQuZGF0YVNvdXJjZS50b3RhbCgpID4gMClcblx0XHR7XG5cdFx0XHRsZXQgZXhwUGFydCA9IHRoaXMuX2dyaWQuZGF0YVNvdXJjZS5hdCgwKTtcblx0XHRcdHRoaXMuX2ZpbHRlckV4cHJlc3Npb24gPSBuZXcgU0ZTMlguTWF0Y2hFeHByZXNzaW9uKGV4cFBhcnQubmFtZSwgZXhwUGFydC5fY29uZGl0aW9uLCBleHBQYXJ0LnZhbHVlKTtcblxuXHRcdFx0Zm9yIChsZXQgaSA9IDE7IGkgPCB0aGlzLl9ncmlkLmRhdGFTb3VyY2UudG90YWwoKTsgaSsrKVxuXHRcdFx0e1xuXHRcdFx0XHRleHBQYXJ0ID0gdGhpcy5fZ3JpZC5kYXRhU291cmNlLmF0KGkpO1xuXG5cdFx0XHRcdGlmIChleHBQYXJ0Lm9wZXJhdG9yID09IFNGUzJYLkxvZ2ljT3BlcmF0b3IuQU5ELmlkKVxuXHRcdFx0XHRcdHRoaXMuX2ZpbHRlckV4cHJlc3Npb24gPSB0aGlzLl9maWx0ZXJFeHByZXNzaW9uLmFuZChleHBQYXJ0Lm5hbWUsIGV4cFBhcnQuX2NvbmRpdGlvbiwgZXhwUGFydC52YWx1ZSk7XG5cdFx0XHRcdGVsc2UgaWYgKGV4cFBhcnQub3BlcmF0b3IgPT0gU0ZTMlguTG9naWNPcGVyYXRvci5PUi5pZClcblx0XHRcdFx0XHR0aGlzLl9maWx0ZXJFeHByZXNzaW9uID0gdGhpcy5fZmlsdGVyRXhwcmVzc2lvbi5vcihleHBQYXJ0Lm5hbWUsIGV4cFBhcnQuX2NvbmRpdGlvbiwgZXhwUGFydC52YWx1ZSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gRmlyZSBldmVudFxuXHRcdGxldCBldnQgPSBuZXcgQ3VzdG9tRXZlbnQodGhpcy5FWFBSRVNTSU9OX1VQREFURURfRVZFTlQsIHtcblx0XHQgICAgXHRkZXRhaWw6IG51bGwsXG5cdFx0XHRcdGJ1YmJsZXM6IGZhbHNlLFxuXHRcdFx0XHRjYW5jZWxhYmxlOiBmYWxzZVxuXHRcdFx0fSk7XG5cblx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoZXZ0KTtcblx0fVxuXG5cdF9vblJlbW92ZUJ0Q2xpY2soKVxuXHR7XG5cdFx0bGV0IGRhdGFJdGVtID0gdGhpcy5fZ3JpZC5kYXRhSXRlbSh0aGlzLl9ncmlkLnNlbGVjdCgpKTtcblx0XHR0aGlzLl9ncmlkLmRhdGFTb3VyY2UucmVtb3ZlKGRhdGFJdGVtKTtcblxuXHRcdC8vIENsZWFyIGdyaWQgc2VsZWN0aW9uXG5cdFx0dGhpcy5fZ3JpZC5jbGVhclNlbGVjdGlvbigpO1xuXG5cdFx0aWYgKHRoaXMuX2dyaWQuZGF0YVNvdXJjZS50b3RhbCgpID09IDApXG5cdFx0e1xuXHRcdFx0Ly8gRGlzYWJsZSBvcGVyYXRvciByYWRpbyBidXR0b25zXG5cdFx0XHR0aGlzLl9lbmFibGVPcGVyYXRvclJiKGZhbHNlKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdC8vIFJlc2V0IG9wZXJhdG9yIG9uIGZpcnN0IGVudHJ5XG5cdFx0XHR0aGlzLl9ncmlkLmRhdGFTb3VyY2UuYXQoMCkub3BlcmF0b3IgPSBudWxsO1xuXHRcdFx0dGhpcy5fZ3JpZC5yZWZyZXNoKCk7XG5cdFx0fVxuXHR9XG5cblx0X29uQ2xlYXJCdENsaWNrKClcblx0e1xuXHRcdC8vIFJlc2V0IGZvcm1cblx0XHQkKCcjYW5kT3BlcmF0b3JSQicsIHRoaXMuX2RpYWxvZykuYXR0cignY2hlY2tlZCcsIHRydWUpO1xuXHRcdCQoJyNvck9wZXJhdG9yUkInLCB0aGlzLl9kaWFsb2cpLmF0dHIoJ2NoZWNrZWQnLCBmYWxzZSk7XG5cdFx0dGhpcy5fZW5hYmxlT3BlcmF0b3JSYihmYWxzZSk7XG5cblx0XHR0aGlzLl92YXJOYW1lQ2IudmFsdWUoJycpO1xuXHRcdHRoaXMuX3R5cGVEZC5zZWxlY3QoMCk7XG5cdFx0dGhpcy5fY29uZGl0aW9uRGQuc2VsZWN0KDApO1xuXG5cdFx0dGhpcy5fdmFsdWVJbi52YWwoJycpO1xuXG5cdFx0Ly8gQ2xlYXIgZ3JpZCBzZWxlY3Rpb25cblx0XHR0aGlzLl9ncmlkLmNsZWFyU2VsZWN0aW9uKCk7XG5cblx0XHQvLyBDbGVhciB0YWJsZVxuXHRcdHRoaXMuX2dyaWQuc2V0RGF0YVNvdXJjZShbXSk7XG5cdH1cblxuXHRfZ2V0RXhwcmVzc2lvblBhcnQodmFyTGFiZWwsIHZhck5hbWUsIHZhclZhbHVlLCB0eXBlTGFiZWwsIGNvbmRpdGlvbiwgb3BlcmF0b3IpXG5cdHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0J2xhYmVsJzogdmFyTGFiZWwsXG5cdFx0XHQnbmFtZSc6IHZhck5hbWUsXG5cdFx0XHQndmFsdWUnOiB2YXJWYWx1ZSxcblx0XHRcdCd0eXBlTGFiZWwnOiB0eXBlTGFiZWwsXG5cdFx0XHQnc3ltYm9sJzogY29uZGl0aW9uLnN5bWJvbCxcblx0XHRcdCdvcGVyYXRvcic6IG9wZXJhdG9yLFxuXHRcdFx0J19jb25kaXRpb24nOiBjb25kaXRpb24sXG5cdFx0fTtcblx0fVxuXG5cdF9lbmFibGVPcGVyYXRvclJiKGVuYWJsZSlcblx0e1xuXHRcdCQoJyNhbmRPcGVyYXRvclJCJywgdGhpcy5fZGlhbG9nKS5hdHRyKCdkaXNhYmxlZCcsICFlbmFibGUpO1xuXHRcdCQoJyNvck9wZXJhdG9yUkInLCB0aGlzLl9kaWFsb2cpLmF0dHIoJ2Rpc2FibGVkJywgIWVuYWJsZSk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdtYXRjaC1leHByZXNzaW9uLWJ1aWxkZXInKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnbWF0Y2gtZXhwcmVzc2lvbi1idWlsZGVyJywgTWF0Y2hFeHByZXNzaW9uQnVpbGRlcik7XG4iLCJleHBvcnQgY2xhc3MgU2lkZWJhckxheW91dCBleHRlbmRzIEhUTUxFbGVtZW50XG57XG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHQgICAgc3VwZXIoKTtcblxuXHRcdC8vIEF0dGFjaCBhIHNoYWRvdyByb290XG5cdFx0Y29uc3Qgc2hhZG93Um9vdCA9IHRoaXMuYXR0YWNoU2hhZG93KHttb2RlOiAnb3Blbid9KTtcblx0XHRzaGFkb3dSb290LmlubmVySFRNTCA9IGBcblx0XHRcdDxzdHlsZT5cblx0XHRcdFx0Omhvc3Qge1xuXHRcdFx0XHRcdGRpc3BsYXk6IGZsZXg7XG5cdFx0XHRcdFx0ZmxleC1kaXJlY3Rpb246IHJvdztcblx0XHRcdFx0fVxuXG5cdFx0XHRcdEBtZWRpYSAobWF4LXdpZHRoOiA1NzUuOThweCkge1xuXHRcdFx0XHRcdDpob3N0KC5zcGxpdC14cykgOjpzbG90dGVkKDpub3QoW2FyaWEtc2VsZWN0ZWQ9XCJ0cnVlXCJdKSkge1xuXHRcdFx0XHRcdFx0ZGlzcGxheTogbm9uZSAhaW1wb3J0YW50O1xuXHRcdFx0XHQgICAgfVxuXG5cdFx0XHRcdFx0Omhvc3QoLnNwbGl0LXhzKSA6OnNsb3R0ZWQoW2FyaWEtc2VsZWN0ZWQ9XCJ0cnVlXCJdKSB7XG5cdFx0XHRcdFx0XHRmbGV4LWdyb3c6IDE7XG5cdFx0XHRcdCAgICB9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRAbWVkaWEgKG1heC13aWR0aDogNzY3Ljk4cHgpIHtcblx0XHRcdFx0XHQ6aG9zdCguc3BsaXQtc20pIDo6c2xvdHRlZCg6bm90KFthcmlhLXNlbGVjdGVkPVwidHJ1ZVwiXSkpIHtcblx0XHRcdFx0XHRcdGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcblx0XHRcdFx0ICAgIH1cblxuXHRcdFx0XHRcdDpob3N0KC5zcGxpdC1zbSkgOjpzbG90dGVkKFthcmlhLXNlbGVjdGVkPVwidHJ1ZVwiXSkge1xuXHRcdFx0XHRcdFx0ZmxleC1ncm93OiAxO1xuXHRcdFx0XHQgICAgfVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0QG1lZGlhIChtYXgtd2lkdGg6IDk5MS45OHB4KSB7XG5cdFx0XHRcdFx0Omhvc3QoLnNwbGl0LW1kKSA6OnNsb3R0ZWQoOm5vdChbYXJpYS1zZWxlY3RlZD1cInRydWVcIl0pKSB7XG5cdFx0XHRcdFx0XHRkaXNwbGF5OiBub25lICFpbXBvcnRhbnQ7XG5cdFx0XHRcdCAgICB9XG5cblx0XHRcdFx0XHQ6aG9zdCguc3BsaXQtbWQpIDo6c2xvdHRlZChbYXJpYS1zZWxlY3RlZD1cInRydWVcIl0pIHtcblx0XHRcdFx0XHRcdGZsZXgtZ3JvdzogMTtcblx0XHRcdFx0ICAgIH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdEBtZWRpYSAobWF4LXdpZHRoOiAxMTk5Ljk4cHgpIHtcblx0XHRcdFx0XHQ6aG9zdCguc3BsaXQtbGcpIDo6c2xvdHRlZCg6bm90KFthcmlhLXNlbGVjdGVkPVwidHJ1ZVwiXSkpIHtcblx0XHRcdFx0XHRcdGRpc3BsYXk6IG5vbmUgIWltcG9ydGFudDtcblx0XHRcdFx0ICAgIH1cblxuXHRcdFx0XHRcdDpob3N0KC5zcGxpdC1sZykgOjpzbG90dGVkKFthcmlhLXNlbGVjdGVkPVwidHJ1ZVwiXSkge1xuXHRcdFx0XHRcdFx0ZmxleC1ncm93OiAxO1xuXHRcdFx0XHQgICAgfVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0LnNpZGUtY29sOjpzbG90dGVkKCopIHtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC5tYWluLWNvbDo6c2xvdHRlZCgqKSB7XG5cdFx0XHRcdFx0ZmxleC1ncm93OiAxO1xuXHRcdFx0XHR9XG5cdFx0XHQ8L3N0eWxlPlxuXG5cdFx0XHQ8c2xvdCBjbGFzcz1cInNpZGUtY29sXCIgbmFtZT1cInNpZGUtY29sdW1uXCI+PC9zbG90PlxuXHRcdFx0PHNsb3QgY2xhc3M9XCJtYWluLWNvbFwiIG5hbWU9XCJtYWluLWNvbHVtblwiPjwvc2xvdD5cblx0XHRgO1xuXG5cdFx0Ly8gU2V0IGluaXRpYWwgc2VsZWN0aW9uXG5cdFx0dGhpcy5zZWxlY3RlZEluZGV4ID0gMDtcblx0fVxuXG5cdGdldCBzZWxlY3RlZFBhbmVsKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9zZWxlY3RlZFBhbmVsO1xuXHR9XG5cblx0c2V0IHNlbGVjdGVkUGFuZWwoZWxlbWVudCkgLy8gJ3NpZGUnIG9yICdtYWluJ1xuXHR7XG5cdFx0aWYgKGVsZW1lbnQgIT0gbnVsbCAmJiBlbGVtZW50LnBhcmVudE5vZGUgPT0gdGhpcylcblx0XHR7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZFBhbmVsID0gZWxlbWVudDtcblxuXHRcdFx0Zm9yIChsZXQgZWxlbWVudCBvZiB0aGlzLmNoaWxkcmVuKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoZWxlbWVudCA9PSB0aGlzLl9zZWxlY3RlZFBhbmVsKVxuXHRcdFx0XHRcdGVsZW1lbnQuc2V0QXR0cmlidXRlKCdhcmlhLXNlbGVjdGVkJywgJ3RydWUnKTtcblx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdGVsZW1lbnQucmVtb3ZlQXR0cmlidXRlKCdhcmlhLXNlbGVjdGVkJyk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRjb25zb2xlLmVycm9yKCdFbGVtZW50IGlzIG5vdCBhIGNoaWxkIG9mIFNpZGViYXJMYXlvdXQnKTtcblx0XHR9XG5cdH1cblxuXHRnZXQgc2VsZWN0ZWRJbmRleCgpXG5cdHtcblx0XHRyZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmNoaWxkcmVuKS5pbmRleE9mKHRoaXMuX3NlbGVjdGVkUGFuZWwpO1xuXHR9XG5cblx0c2V0IHNlbGVjdGVkSW5kZXgoaW5kZXgpXG5cdHtcblx0XHRpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiAwKVxuXHRcdHtcblx0XHRcdGlmICh0aGlzLmNoaWxkcmVuW2luZGV4XSA9PSBudWxsKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25zb2xlLmVycm9yKCdJbnZhbGlkIFNpZGViYXJMYXlvdXQgaW5kZXgnKTtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRsZXQgZWxlbWVudCA9IHRoaXMuY2hpbGRyZW5baW5kZXhdO1xuXHRcdFx0dGhpcy5zZWxlY3RlZFBhbmVsID0gZWxlbWVudDtcblx0XHR9XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdzaWRlYmFyLWxheW91dCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdzaWRlYmFyLWxheW91dCcsIFNpZGViYXJMYXlvdXQpO1xuIiwiaW1wb3J0IHtCYXNlTW9kdWxlfSBmcm9tICcuL2Jhc2UtbW9kdWxlJztcbmltcG9ydCB7U2lkZWJhckxheW91dH0gZnJvbSAnLi4vY29tcG9uZW50cy9zaWRlYmFyLWxheW91dCc7XG5pbXBvcnQge01hdGNoRXhwcmVzc2lvbkJ1aWxkZXJ9IGZyb20gJy4uL2NvbXBvbmVudHMvbW9kdWxlLXNwZWNpZmljL21hdGNoLWV4cHJlc3Npb24tYnVpbGRlcic7XG5pbXBvcnQge0NvbmZpZ0ludGVyZmFjZUJ1aWxkZXJ9IGZyb20gJy4uL3V0aWxzL3VpYnVpbGRlci9jb25maWctaW50ZXJmYWNlLWJ1aWxkZXInO1xuaW1wb3J0IHtjYXBpdGFsaXplRmlyc3QsIGZpbHRlckNsYXNzTmFtZSwgcm91bmRUb0RlY2ltYWxzLCBzY2FsZUJ5dGVzfSBmcm9tICcuLi91dGlscy91dGlsaXRpZXMnO1xuaW1wb3J0IHtSb29tUHJvcGVydGllc0RhdGEsVXNlclByb3BlcnRpZXNEYXRhfSBmcm9tICcuLi91dGlscy9tYXRjaC1wcm9wZXJ0aWVzJztcbmltcG9ydCB7VXNlckNvdW50Q2hhcnR9IGZyb20gJy4uL2NvbXBvbmVudHMvY2hhcnRzL3VzZXItY291bnQtY2hhcnQnO1xuaW1wb3J0IHtnZXRUaW1lUmFuZ2VUb29sdGlwVGVtcGxhdGUsIGdldFdSQnl0ZXNMYWJlbFRlbXBsYXRlfSBmcm9tICcuLi9jb21wb25lbnRzL2NoYXJ0cy9jaGFydC11dGlscyc7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFpvbmVNb25pdG9yIGV4dGVuZHMgQmFzZU1vZHVsZVxue1xuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0ICAgIHN1cGVyKCd6b25lTW9uaXRvcicpO1xuXG5cdFx0dGhpcy5NT05JVE9SRURfVFlQRV9aT05FID0gJ3pvbmUnO1xuXHRcdHRoaXMuTU9OSVRPUkVEX1RZUEVfUk9PTSA9ICdyb29tJztcblx0XHR0aGlzLk1PTklUT1JFRF9UWVBFX1VTRVIgPSAndXNlcic7XG5cblx0XHR0aGlzLkFOWV9MQUJFTCA9ICdbYW55XSc7XG5cdFx0dGhpcy5ERUZBVUxUX0dST1VQX05BTUUgPSAnZGVmYXVsdCc7XG5cdFx0dGhpcy5NQVhfRVhURU5TSU9OX0xPR19TSVpFID0gMzAwO1xuXHRcdHRoaXMuS0lDS19CQU5fREVGQVVMVF9ERUxBWSA9IDU7XG5cblx0XHQvLyBPdXRnb2luZyByZXF1ZXN0c1xuXHRcdHRoaXMuUkVRX0dFVF9EQVRBID0gJ2dldERhdGEnO1xuXHRcdHRoaXMuUkVRX1NFVF9aT05FX1NFVFRJTkdTID0gJ3NldFpvbmVTZXR0aW5ncyc7XG5cdFx0dGhpcy5SRVFfU0VUX1JPT01fU0VUVElOR1MgPSAnc2V0Um9vbVNldHRpbmdzJztcblx0XHR0aGlzLlJFUV9TRVRfVVNFUl9TRVRUSU5HUyA9ICdzZXRVc2VyU2V0dGluZ3MnO1xuXHRcdHRoaXMuUkVRX1JFTE9BRF9aT05FX0VYVCA9ICdyZWxvYWRab25lRXh0Jztcblx0XHR0aGlzLlJFUV9SRUxPQURfV09SRFMgPSAncmVsb2FkV29yZHMnO1xuXHRcdHRoaXMuUkVRX0RJU0NPTk5FQ1RfVVNFUiA9ICdkaXNjb25uVXNlcic7XG5cdFx0dGhpcy5SRVFfS0lDS19VU0VSID0gJ2tpY2tVc2VyJztcblx0XHR0aGlzLlJFUV9CQU5fVVNFUiA9ICdiYW5Vc2VyJztcblx0XHR0aGlzLlJFUV9HRVRfUk9PTV9DT05GSUcgPSAnZ2V0Um9vbUNvbmZpZyc7XG5cdFx0dGhpcy5SRVFfQ1JFQVRFX1JPT00gPSAnY3JlYXRlUm9vbSc7XG5cdFx0dGhpcy5SRVFfUkVNT1ZFX1JPT00gPSAncmVtb3ZlUm9vbSc7XG5cdFx0dGhpcy5SRVFfQURNSU5fTVNHID0gJ2FkbWluTXNnJztcblxuXHRcdC8vIEluY29taW5nIHJlc3BvbnNlc1xuXHRcdHRoaXMuUkVTUF9EQVRBID0gJ2RhdGEnO1xuXHRcdHRoaXMuUkVTUF9VTkVYUEVDVEVEX0VSUk9SID0gJ3VuZXhwRXJyb3InO1xuXHRcdHRoaXMuUkVTUF9VUERBVEVfRVJST1IgPSAndXBkYXRlRXJyb3InO1xuXHRcdHRoaXMuUkVTUF9ST09NX0NPTkZJRyA9ICdyb29tQ29uZmlnJztcblx0XHR0aGlzLlJFU1BfUk9PTV9DT05GSUdfRVJST1IgPSAncm9vbUNvbmZpZ0Vycic7XG5cdFx0dGhpcy5SRVNQX1JPT01fQ1JFQVRFRCA9ICdyb29tQ3JlYXRlZCc7XG5cdFx0dGhpcy5SRVNQX1JPT01fQ1JFQVRJT05fRVJST1IgPSAncm9vbUVycm9yJztcblx0XHR0aGlzLlJFU1BfTE9HX01FU1NBR0VTID0gJ2xvZyc7IC8vIFRoaXMgcmVzcG9uc2UgZG9lc24ndCBoYXZlIGEgY29ycmVzcG9uZGluZyByZXF1ZXN0IGJlY2F1c2UgaXQgaXMgbWFuYWdlZCBieSBhIHNlcnZlciBldmVudCBsaXN0ZW5lclxuXG5cdFx0dGhpcy5fY3VycmVudFJlcXVlc3RJZCA9IC0xO1xuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8gQ09NTU9OIE1PRFVMRSBJTlRFUkZBQ0UgTUVUSE9EU1xuXHQvLyBUaGlzIG1lbWJlcnMgYXJlIHVzZWQgYnkgdGhlIG1haW4gY29udHJvbGxlclxuXHQvLyB0byBjb21tdW5pY2F0ZSB3aXRoIHRoZSBtb2R1bGUncyBjb250cm9sbGVyLlxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdGluaXRpYWxpemUoaWREYXRhLCBzaGVsbENvbnRyb2xsZXIpXG5cdHtcblx0XHQvLyBDYWxsIHN1cGVyIG1ldGhvZFxuXHRcdHN1cGVyLmluaXRpYWxpemUoaWREYXRhLCBzaGVsbENvbnRyb2xsZXIpO1xuXG5cdFx0Ly8gU2V0IG1vbml0b3JpbmcgaW50ZXJmYWNlXG5cdFx0dGhpcy5fc2V0TW9uaXRvcmluZ0ludGVyZmFjZSgpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBwcm9ncmVzcyBiYXJcblx0XHQkKCcjem5tLXByb2dyZXNzQmFyJykua2VuZG9Qcm9ncmVzc0Jhcih7XG5cdFx0XHRtaW46IDAsXG4gICAgICAgICAgICBtYXg6IDEwMCxcblx0XHRcdHZhbHVlOiBmYWxzZSxcbiAgICAgICAgICAgIHR5cGU6ICd2YWx1ZScsXG4gICAgICAgICAgICBhbmltYXRpb246IHtcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNDAwXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG5cdFx0Ly8gTElTVFNcblxuXHRcdC8vIEluaXRpYWxpemUgaW50ZXJ2YWwgZHJvcGRvd25cblx0XHR0aGlzLl9pbnRlcnZhbERyb3BEb3duID0gJCgnI3pubS1pbnRlcnZhbEREJykua2VuZG9Ecm9wRG93bkxpc3Qoe1xuXHRcdFx0dmFsdWVUZW1wbGF0ZTogJzxzcGFuIGNsYXNzPVwidGV4dC1tdXRlZCBwci0xXCI+SW50ZXJ2YWw6PC9zcGFuPjxzcGFuPiM6ZGF0YS50ZXh0Izwvc3Bhbj4nLFxuXHRcdFx0Y2hhbmdlOiAkLnByb3h5KHRoaXMuX29uVXBkYXRlSW50ZXJ2YWxDaGFuZ2UsIHRoaXMpXG5cdFx0fSkuZGF0YSgna2VuZG9Ecm9wRG93bkxpc3QnKTtcblxuXHRcdC8vIEluaXRpYWxpemUgcGFuZSBiYXJcblx0XHR0aGlzLl9hY2NvcmRpb24gPSAkKCcjem5tLXBhbmVsYmFyJykua2VuZG9QYW5lbEJhcih7XG4gICAgICAgICAgICBleHBhbmRNb2RlOiAnc2luZ2xlJyxcblx0XHRcdGNoYW5nZTogJC5wcm94eSh0aGlzLl9vbkVudGl0aWVzUGFuZWxDaGFuZ2UsIHRoaXMpXG4gICAgICAgIH0pLmRhdGEoJ2tlbmRvUGFuZWxCYXInKTtcblxuXHRcdC8vIEluaXRpYWxpemUgbGlzdHNcblx0XHR0aGlzLl96b25lTGlzdEJveCA9ICQoXCIjem5tLXpvbmVMaXN0XCIpLmtlbmRvTGlzdEJveCh7XG5cdFx0XHR0ZW1wbGF0ZTogJzxkaXY+IzpkYXRhLm5hbWUjICgjOmRhdGEudXNlcnMjKTwvZGl2PicsXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25ab25lU2VsZWN0ZWQsIHRoaXMpXG5cdFx0fSkuZGF0YSgna2VuZG9MaXN0Qm94Jyk7XG5cblx0XHR0aGlzLl96b25lTGlzdEJveC53cmFwcGVyLmZpbmQoJy5rLWxpc3QnKS5vbignZGJsY2xpY2snLCAnLmstaXRlbScsICQucHJveHkodGhpcy5fb25Nb25pdG9yU2VsZWN0aW9uQnRDbGljaywgdGhpcykpO1xuXG5cdFx0dGhpcy5fcm9vbUxpc3RCb3ggPSAkKFwiI3pubS1yb29tTGlzdFwiKS5rZW5kb0xpc3RCb3goe1xuXHRcdFx0dGVtcGxhdGU6ICc8ZGl2PiM6ZGF0YS5uYW1lIyAoIzpkYXRhLnVzZXJzIyk8L2Rpdj4nLFxuXHRcdFx0Y2hhbmdlOiAkLnByb3h5KHRoaXMuX29uUm9vbVNlbGVjdGVkLCB0aGlzKVxuXHRcdH0pLmRhdGEoJ2tlbmRvTGlzdEJveCcpO1xuXG5cdFx0dGhpcy5fcm9vbUxpc3RCb3gud3JhcHBlci5maW5kKCcuay1saXN0Jykub24oJ2RibGNsaWNrJywgJy5rLWl0ZW0nLCAkLnByb3h5KHRoaXMuX29uTW9uaXRvclNlbGVjdGlvbkJ0Q2xpY2ssIHRoaXMpKTtcblxuXHRcdHRoaXMuX3VzZXJMaXN0Qm94ID0gJChcIiN6bm0tdXNlckxpc3RcIikua2VuZG9MaXN0Qm94KHtcblx0XHRcdHRlbXBsYXRlOiAnPGRpdj4jOmRhdGEubmFtZSM8L2Rpdj4nLFxuXHRcdFx0Y2hhbmdlOiAkLnByb3h5KHRoaXMuX29uVXNlclNlbGVjdGVkLCB0aGlzKVxuXHRcdH0pLmRhdGEoJ2tlbmRvTGlzdEJveCcpO1xuXG5cdFx0dGhpcy5fdXNlckxpc3RCb3gud3JhcHBlci5maW5kKCcuay1saXN0Jykub24oJ2RibGNsaWNrJywgJy5rLWl0ZW0nLCAkLnByb3h5KHRoaXMuX29uTW9uaXRvclNlbGVjdGlvbkJ0Q2xpY2ssIHRoaXMpKTtcblxuXHRcdC8vIEluaXRpYWxpemUgUm9vbSBHcm91cHMgZHJvcGRvd25cblx0XHR0aGlzLl9ncm91cHNEcm9wRG93biA9ICQoJyN6bm0tcm9vbUdyb3Vwc0REJykua2VuZG9Ecm9wRG93bkxpc3Qoe1xuXHRcdFx0ZGF0YVRleHRGaWVsZDogJ2xhYmVsJyxcbiAgXHRcdFx0ZGF0YVZhbHVlRmllbGQ6ICduYW1lJyxcblx0XHRcdGNoYW5nZTogJC5wcm94eSh0aGlzLl9vbkdyb3VwQ2hhbmdlLCB0aGlzKVxuXHRcdH0pLmRhdGEoJ2tlbmRvRHJvcERvd25MaXN0Jyk7XG5cblx0XHQvLyBCdWlsZCBpbml0aWFsIGdyb3VwcyBsaXN0XG5cdFx0dGhpcy5fc2V0R3JvdXBzRGF0YVByb3ZpZGVyKG51bGwpO1xuXG5cdFx0Ly8gQ3JlYXRlIGludGVyZmFjZSBidWlsZGVyIGluc3RhbmNlc1xuXHRcdHRoaXMuX2ludGVyZmFjZUJ1aWxkZXIgPSBuZXcgQ29uZmlnSW50ZXJmYWNlQnVpbGRlcigpO1xuXHRcdHRoaXMuX3Jvb21DcmVhdGlvbklCdWlsZGVyID0gbmV3IENvbmZpZ0ludGVyZmFjZUJ1aWxkZXIoKTtcblxuXHRcdC8vIEFkZCBsaXN0ZW5lciB0byBzaG93IGxpbWl0IHdhcm5pbmcgdG9vbHRpcHNcblx0XHQkKCcjem5tLXBhbmVsYmFyJykua2VuZG9Ub29sdGlwKHtcblx0XHRcdGZpbHRlcjogJ2lbdGl0bGVdLmxpbWl0LXdhcm5pbmcnLFxuXHRcdFx0cG9zaXRpb246ICdyaWdodCcsXG5cdFx0XHR3aWR0aDogJzI1MHB4Jyxcblx0XHRcdGNvbnRlbnQ6IGZ1bmN0aW9uKGUpIHtcblx0XHRcdFx0cmV0dXJuIGA8ZGl2IGNsYXNzPVwiaGVscC10b29sdGlwXCI+JHtlLnRhcmdldC5kYXRhKCd0aXRsZScpfTwvZGl2PmA7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvLyBST09NIENSRUFUSU9OIFBBTkVMXG5cblx0XHQvLyBBZGQgY2xpY2sgbGlzdGVuZXIgdG8gQ3JlYXRlICYgUmVtb3ZlIFJvb20gYnV0dG9uc1xuXHRcdCQoJyN6bm0tY3JlYXRlUm9vbUJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbkNyZWF0ZVJvb21CdENsaWNrLCB0aGlzKSk7XG5cdFx0JCgnI3pubS1yZW1vdmVSb29tQnQnKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uUmVtb3ZlUm9vbUJ0Q2xpY2ssIHRoaXMpKTtcblxuXHRcdC8vIENvbmZpZ3VyZSByb29tIGNyZWF0aW9uIHBhbmVsXG5cdFx0JCgnI3pubS1jcmVhdGVSb29tTW9kYWwnKS5tb2RhbCh7XG5cdFx0XHRiYWNrZHJvcDogJ3N0YXRpYycsXG5cdFx0XHRrZXlib2FyZDogZmFsc2UsXG5cdFx0XHRzaG93OiBmYWxzZSxcblx0XHR9KTtcblxuXHRcdC8vIEFkZCBsaXN0ZW5lciBmb3Igcm9vbSBjcmVhdGlvbiBwYW5lbCdzIGNyZWF0ZSBidXR0b24gY2xpY2tcblx0XHQkKCcjem5tLXJvb21DcmVhdG9yQ3JlYXRlQnQnKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uUm9vbUNyZWF0b3JDcmVhdGVCdENsaWNrLCB0aGlzKSk7XG5cblx0XHQvLyBBZGQgbGlzdGVuZXIgZm9yIHJvb20gY3JlYXRpb24gcGFuZWwgaGlkZVxuXHRcdCQoJyN6bm0tY3JlYXRlUm9vbU1vZGFsJykub24oJ2hpZGRlbi5icy5tb2RhbCcsICQucHJveHkodGhpcy5fb25DcmVhdGVSb29tTW9kYWxIaWRkZW4sIHRoaXMpKTtcblxuXHRcdC8vIFJPT00gJiBVU0VSIEZJTFRFUklORyBQQU5FTFNcblxuXHRcdC8vIFNldHVwIG1hdGNoIGV4cHJlc3Npb24gYnVpbGRlciBwYW5lbCBmb3Igcm9vbXNcblx0XHR0aGlzLl9yb29tRmlsdGVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3pubS1yb29tRmlsdGVyJyk7XG5cdFx0dGhpcy5fcm9vbUZpbHRlci50aXRsZSA9ICdSb29tIEZpbHRlciBFeHByZXNzaW9uIEJ1aWxkZXInO1xuXHRcdHRoaXMuX3Jvb21GaWx0ZXIucHJlZGVmaW5lZFZhck5hbWVzID0gUm9vbVByb3BlcnRpZXNEYXRhLnByb3BlcnRpZXNBcnJheTtcblx0XHQkKHRoaXMuX3Jvb21GaWx0ZXIpLm9uKHRoaXMuX3Jvb21GaWx0ZXIuRVhQUkVTU0lPTl9VUERBVEVEX0VWRU5ULCAkLnByb3h5KHRoaXMuX29uUm9vbUZpbHRlclVwZGF0ZWQsIHRoaXMpKTtcblxuXHRcdCQoJyN6bm0tZmlsdGVyUm9vbUJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vblNob3dSb29tRmlsdGVyQnRDbGljaywgdGhpcykpO1xuXHRcdCQoJyN6bm0tYXBwbHlSb29tRmlsdGVyQ0InKS5vbignY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vbkFwcGx5QnRDaGFuZ2UsIHRoaXMpKTtcblxuXHRcdC8vIFNldHVwIG1hdGNoIGV4cHJlc3Npb24gYnVpbGRlciBwYW5lbCBmb3IgdXNlcnNcblx0XHR0aGlzLl91c2VyRmlsdGVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3pubS11c2VyRmlsdGVyJyk7XG5cdFx0dGhpcy5fdXNlckZpbHRlci50aXRsZSA9ICdVc2VyIEZpbHRlciBFeHByZXNzaW9uIEJ1aWxkZXInO1xuXHRcdHRoaXMuX3VzZXJGaWx0ZXIucHJlZGVmaW5lZFZhck5hbWVzID0gVXNlclByb3BlcnRpZXNEYXRhLnByb3BlcnRpZXNBcnJheTtcblx0XHQkKHRoaXMuX3VzZXJGaWx0ZXIpLm9uKHRoaXMuX3VzZXJGaWx0ZXIuRVhQUkVTU0lPTl9VUERBVEVEX0VWRU5ULCAkLnByb3h5KHRoaXMuX29uVXNlckZpbHRlclVwZGF0ZWQsIHRoaXMpKTtcblxuXHRcdCQoJyN6bm0tZmlsdGVyVXNlckJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vblNob3dVc2VyRmlsdGVyQnRDbGljaywgdGhpcykpO1xuXHRcdCQoJyN6bm0tYXBwbHlVc2VyRmlsdGVyQ0InKS5vbignY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vbkFwcGx5QnRDaGFuZ2UsIHRoaXMpKTtcblxuXHRcdC8vIE1BSU4gQ09OVFJPTFNcblxuXHRcdCQoJyN6bm0tbW9uaXRvckJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbk1vbml0b3JTZWxlY3Rpb25CdENsaWNrLCB0aGlzKSk7XG5cdFx0JCgnI3pubS1zZW5kTWVzc2FnZUJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vblNlbmRBZG1pbk1zZ0J0Q2xpY2ssIHRoaXMpKTtcblx0XHQkKCcjem5tLW1lc3NhZ2VJbicpLm9uKCdrZXl1cCcsICQucHJveHkodGhpcy5fb25TZW5kQWRtaW5Nc2dJbktleVVwLCB0aGlzKSk7XG5cblx0XHQvLyBNT05JVE9SSU5HIENPTlRST0xTXG5cblx0XHQkKCcjem5tLWNsb3NlTW9uaXRvckJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbkNsb3NlTW9uaXRvckJ0Q2xpY2ssIHRoaXMpKTtcblx0XHQkKCcjem5tLWVkaXRCdCcpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25FZGl0QnRDbGljaywgdGhpcykpO1xuXHRcdCQoJyN6bm0tY2FuY2VsQnQnKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uQ2FuY2VsQnRDbGljaywgdGhpcykpO1xuXHRcdCQoJyN6bm0tc3VibWl0QnQnKS5vbignY2xpY2snLCAkLnByb3h5KHRoaXMuX29uU3VibWl0QnRDbGljaywgdGhpcykpO1xuXG5cdFx0Ly8gSGlkZSBlZGl0IGNvbnRyb2xzXG5cdFx0JCgnI3pubS1lZGl0Q29udHJvbHMnKS5oaWRlKCk7XG5cblx0XHQvLyBaT05FIE1PTklUT1IgLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHQvLyBTZXQgcmVmZXJlbmNlIHRvIHVzZXIgY291bnQgY2hhcnRcblx0XHR0aGlzLl91c2VyQ291bnRDaGFydCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd6bm0tdXNlckNvdW50Q2hhcnQnKTtcblxuXHRcdC8vIEluaXRpYWxpemUgdGltZSByYW5nZSBzbGlkZXJcblx0XHR0aGlzLl90aW1lU2xpZGVyID0gJCgnI3pubS10aW1lU2xpZGVyJykua2VuZG9SYW5nZVNsaWRlcih7XG5cdFx0XHRtaW46IC0yNCxcbiAgICAgICAgICAgIG1heDogMCxcbiAgICAgICAgICAgIHNtYWxsU3RlcDogMSxcbiAgICAgICAgICAgIGxhcmdlU3RlcDogMCxcblx0XHRcdGNoYW5nZTogJC5wcm94eSh0aGlzLl9vblRpbWVSYW5nZUNoYW5nZSwgdGhpcyksXG5cdFx0XHR0b29sdGlwOiB7XG5cdFx0XHRcdHRlbXBsYXRlOiBnZXRUaW1lUmFuZ2VUb29sdGlwVGVtcGxhdGUoKVxuXHRcdFx0fSxcblx0XHRcdGxlZnREcmFnSGFuZGxlVGl0bGU6ICdEcmFnJyxcblx0XHRcdHJpZ2h0RHJhZ0hhbmRsZVRpdGxlOiAnRHJhZycsXG5cdFx0fSkuZGF0YSgna2VuZG9SYW5nZVNsaWRlcicpO1xuXG5cdFx0Ly8gUmVzZXQgdGltZSByYW5nZSBvbiB1c2VyIGNvdW50IGNoYXJ0XG5cdFx0dGhpcy5fb25UaW1lUmFuZ2VDaGFuZ2UoKTtcblxuXHRcdC8vIEFkZCBidXR0b24gY2xpY2sgbGlzdGVuZXJzXG5cdFx0JCgnI3pubS1yZWxvYWRXb3Jkc0J0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbldvcmRzUmVsb2FkQnRDbGljaywgdGhpcykpO1xuXHRcdCQoJyN6bm0tcmVsb2FkWm9uZUV4dEJ0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vblpvbmVFeHRSZWxvYWRCdENsaWNrLCB0aGlzKSk7XG5cblx0XHQvLyBJbml0aWFsaXplIGV4dGVuc2lvbiBsb2cgZ3JpZFxuXHRcdHRoaXMuX3pvbmVFeHRMb2dHcmlkID0gJCgnI3pubS16b25lRXh0TG9nR3JpZCcpLmtlbmRvR3JpZCh7XG5cdFx0XHRkYXRhU291cmNlOiBbXSxcblx0XHRcdHJlc2l6YWJsZTogdHJ1ZSxcblx0XHRcdHNlbGVjdGFibGU6IGZhbHNlLFxuXHRcdFx0bm9SZWNvcmRzOiB7XG5cdFx0XHRcdHRlbXBsYXRlOiAnTm8gZW50cmllcy4nXG5cdFx0XHR9LFxuXHRcdFx0Y29sdW1uczogW1xuXHRcdFx0XHR7XG5cdFx0XHRcdFx0ZmllbGQ6ICd0aW1lc3RhbXAnLFxuXHRcdFx0XHRcdHRpdGxlOiAnVGltZXN0YW1wJyxcblx0XHRcdFx0XHR3aWR0aDogMTgwXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRmaWVsZDogJ2xldmVsJyxcblx0XHRcdFx0XHR0aXRsZTogJ0xldmVsJyxcblx0XHRcdFx0XHR3aWR0aDogMTAwXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRmaWVsZDogJ21lc3NhZ2UnLFxuXHRcdFx0XHRcdHRpdGxlOiAnTWVzc2FnZScsXG5cdFx0XHRcdFx0d2lkdGg6IDQwMFxuXHRcdFx0XHR9LFxuXHRcdFx0XSxcblx0XHRcdGRhdGFCb3VuZDogZnVuY3Rpb24oKSB7XG5cdFx0XHQgICAgdGhpcy5jb250ZW50LnNjcm9sbFRvcCh0aGlzLnRib2R5LmhlaWdodCgpKTsgLy8gU2Nyb2xsIHRvIGJvdHRvbVxuXHRcdFx0fVxuXHRcdH0pLmRhdGEoJ2tlbmRvR3JpZCcpO1xuXG5cdFx0Ly8gUk9PTSBNT05JVE9SIC0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBleHRlbnNpb24gbG9nIGdyaWRcblx0XHR0aGlzLl9yb29tRXh0TG9nR3JpZCA9ICQoJyN6bm0tcm9vbUV4dExvZ0dyaWQnKS5rZW5kb0dyaWQoe1xuXHRcdFx0ZGF0YVNvdXJjZTogW10sXG5cdFx0XHRyZXNpemFibGU6IHRydWUsXG5cdFx0XHRzZWxlY3RhYmxlOiBmYWxzZSxcblx0XHRcdG5vUmVjb3Jkczoge1xuXHRcdFx0XHR0ZW1wbGF0ZTogJ05vIGVudHJpZXMuJ1xuXHRcdFx0fSxcblx0XHRcdGNvbHVtbnM6IFtcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGZpZWxkOiAndGltZXN0YW1wJyxcblx0XHRcdFx0XHR0aXRsZTogJ1RpbWVzdGFtcCcsXG5cdFx0XHRcdFx0d2lkdGg6IDE4MFxuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0ZmllbGQ6ICdsZXZlbCcsXG5cdFx0XHRcdFx0dGl0bGU6ICdMZXZlbCcsXG5cdFx0XHRcdFx0d2lkdGg6IDEwMFxuXHRcdFx0XHR9LFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0ZmllbGQ6ICdtZXNzYWdlJyxcblx0XHRcdFx0XHR0aXRsZTogJ01lc3NhZ2UnLFxuXHRcdFx0XHRcdHdpZHRoOiA0MDBcblx0XHRcdFx0fSxcblx0XHRcdF0sXG5cdFx0XHRkYXRhQm91bmQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0ICAgIHRoaXMuY29udGVudC5zY3JvbGxUb3AodGhpcy50Ym9keS5oZWlnaHQoKSk7IC8vIFNjcm9sbCB0byBib3R0b21cblx0XHRcdH1cblx0XHR9KS5kYXRhKCdrZW5kb0dyaWQnKTtcblxuXHRcdC8vIFVTRVIgTU9OSVRPUiAtLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRcdHRoaXMuX2tpY2tEZWxheUluID0gJCgnI3pubS1raWNrRGVsYXlOUycpLmtlbmRvTnVtZXJpY1RleHRCb3goe1xuXHRcdCAgICBtaW46IDAsXG5cdFx0ICAgIHN0ZXA6IDEsXG5cdFx0ICAgIGZvcm1hdDogJyMnLFxuXHRcdFx0cGxhY2Vob2xkZXI6ICdEZWxheSAocyknXG5cdFx0fSkuZGF0YSgna2VuZG9OdW1lcmljVGV4dEJveCcpO1xuXG5cdFx0dGhpcy5fYmFuTW9kZURkID0gJCgnI3pubS1iYW5Nb2RlREQnKS5rZW5kb0Ryb3BEb3duTGlzdCh7XG5cdFx0XHRkYXRhU291cmNlOiBbJ0lQJywgJ05BTUUnXSxcblx0XHRcdGF1dG9XaWR0aDogdHJ1ZSxcblx0XHRcdG9wdGlvbkxhYmVsOiB7XG5cdFx0XHRcdHRleHQ6ICdNb2RlJ1xuXHRcdFx0fSxcblx0XHRcdG9wdGlvbkxhYmVsVGVtcGxhdGU6ICc8c3BhbiBjbGFzcz1cInRleHQtbXV0ZWRcIj4jOnRleHQjPC9zcGFuPicsXG5cdFx0fSkuZGF0YSgna2VuZG9Ecm9wRG93bkxpc3QnKTtcblxuXHRcdHRoaXMuX2JhbkR1clVuaXREZCA9ICQoJyN6bm0tYmFuRHVyYXRpb25Vbml0REQnKS5rZW5kb0Ryb3BEb3duTGlzdCh7XG5cdFx0XHRhdXRvV2lkdGg6IHRydWUsXG5cdFx0fSkuZGF0YSgna2VuZG9Ecm9wRG93bkxpc3QnKTtcblxuXHRcdHRoaXMuX2JhbkR1cmF0aW9uSW4gPSAkKCcjem5tLWJhbkR1cmF0aW9uTlMnKS5rZW5kb051bWVyaWNUZXh0Qm94KHtcblx0XHQgICAgbWluOiAxLFxuXHRcdCAgICBzdGVwOiAxLFxuXHRcdCAgICBmb3JtYXQ6ICcjJyxcblx0XHRcdHBsYWNlaG9sZGVyOiAnRHVyYXRpb24nXG5cdFx0fSkuZGF0YSgna2VuZG9OdW1lcmljVGV4dEJveCcpO1xuXG5cdFx0dGhpcy5fYmFuRGVsYXlJbiA9ICQoJyN6bm0tYmFuRGVsYXlOUycpLmtlbmRvTnVtZXJpY1RleHRCb3goe1xuXHRcdCAgICBtaW46IDAsXG5cdFx0ICAgIHN0ZXA6IDEsXG5cdFx0ICAgIGZvcm1hdDogJyMnLFxuXHRcdFx0cGxhY2Vob2xkZXI6ICdEZWxheSAocyknXG5cdFx0fSkuZGF0YSgna2VuZG9OdW1lcmljVGV4dEJveCcpO1xuXG5cdFx0Ly8gQWRkIGJ1dHRvbiBjbGljayBsaXN0ZW5lcnNcblx0XHQkKCcjem5tLWRpc2Nvbm5lY3RCdCcpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25EaXNjb25uZWN0QnRDbGljaywgdGhpcykpO1xuXHRcdCQoJyN6bm0ta2lja0J0Jykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbktpY2tCdENsaWNrLCB0aGlzKSk7XG5cdFx0JCgnI3pubS1iYW5CdCcpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25CYW5CdENsaWNrLCB0aGlzKSk7XG5cblx0XHQvLyBDaGFydHNcblxuXHRcdHRoaXMuX3BhY2tldFF1ZXVlQ2hhcnQgPSAkKCcjem5tLXBhY2tldFF1ZXVlQ2hhcnQnKS5rZW5kb0NoYXJ0KHtcblx0XHRcdHRyYW5zaXRpb25zOiBmYWxzZSxcblx0XHRcdGNoYXJ0QXJlYToge1xuXHRcdFx0XHRoZWlnaHQ6IDEwMFxuXHRcdFx0fSxcblx0ICAgICAgICBsZWdlbmQ6IHtcblx0ICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICB9LFxuXHQgICAgICAgIHNlcmllc0RlZmF1bHRzOiB7XG5cdCAgICAgICAgICAgIHR5cGU6ICdiYXInLFxuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IHRydWUsXG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0lJyxcblx0ICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCcsXG5cdFx0XHRcdFx0cG9zaXRpb246ICdpbnNpZGVCYXNlJ1xuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRnYXA6IC41LFxuXHRcdFx0XHRzcGFjaW5nOiAwLFxuXHRcdFx0XHRvdmVybGF5OiB7XG5cdFx0XHRcdFx0Z3JhZGllbnQ6ICdub25lJ1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRib3JkZXI6IHtcblx0XHRcdFx0XHR3aWR0aDogMFxuXHRcdFx0XHR9XG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXM6IFtcblx0XHRcdFx0e1xuXHRcdFx0XHRcdG5hbWU6ICdQYWNrZXQgcXVldWUnLFxuXHRcdCAgICAgICAgICAgIGZpZWxkOiAndmFsdWUnLFxuXHRcdCAgICAgICAgICAgIGNhdGVnb3J5RmllbGQ6ICdjYXRlZ29yeScsXG5cdFx0XHRcdFx0Y29sb3I6ICcjRkI3RDMzJ1xuXHRcdCAgICAgICAgfVxuXHRcdFx0XSxcblx0ICAgICAgICB2YWx1ZUF4aXM6IHtcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0lJ1xuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgICBsaW5lOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaW46IDAsXG5cdCAgICBcdFx0bWF4OiAxMDBcblx0ICAgICAgICB9LFxuXHQgICAgICAgIGNhdGVnb3J5QXhpczoge1xuXHQgICAgICAgICAgICBtYWpvckdyaWRMaW5lczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWFqb3JUaWNrczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGxhYmVsczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHRcdFx0dG9vbHRpcDoge1xuXHRcdFx0XHR2aXNpYmxlOiBmYWxzZSxcblx0ICAgICAgICB9XG5cdCAgICB9KS5kYXRhKCdrZW5kb0NoYXJ0Jyk7XG5cblx0XHR0aGlzLl9kcm9wcGVkTXNnQ2hhcnQgPSAkKCcjem5tLWRyb3BwZWRNc2dDaGFydCcpLmtlbmRvQ2hhcnQoe1xuXHRcdFx0dHJhbnNpdGlvbnM6IGZhbHNlLFxuXHRcdFx0Y2hhcnRBcmVhOiB7XG5cdFx0XHRcdGhlaWdodDogMTAwXG5cdFx0XHR9LFxuXHQgICAgICAgIGxlZ2VuZDoge1xuXHQgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzRGVmYXVsdHM6IHtcblx0ICAgICAgICAgICAgdHlwZTogJ2JhcicsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogdHJ1ZSxcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG5cdCAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiAndHJhbnNwYXJlbnQnLFxuXHRcdFx0XHRcdHBvc2l0aW9uOiAnaW5zaWRlQmFzZScsXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdGdhcDogLjUsXG5cdFx0XHRcdHNwYWNpbmc6IDAsXG5cdFx0XHRcdG92ZXJsYXk6IHtcblx0XHRcdFx0XHRncmFkaWVudDogJ25vbmUnXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGJvcmRlcjoge1xuXHRcdFx0XHRcdHdpZHRoOiAwXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHQgICAgICAgIHNlcmllczogW1xuXHRcdFx0XHR7XG5cdFx0XHRcdFx0bmFtZTogJ0Ryb3BwZWQgbWVzc2FnZXMnLFxuXHRcdCAgICAgICAgICAgIGZpZWxkOiAndmFsdWUnLFxuXHRcdCAgICAgICAgICAgIGNhdGVnb3J5RmllbGQ6ICdjYXRlZ29yeScsXG5cdFx0XHRcdFx0Y29sb3I6ICcjRkI3RDMzJ1xuXHRcdCAgICAgICAgfVxuXHRcdFx0XSxcblx0ICAgICAgICB2YWx1ZUF4aXM6IHtcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICBmb3JtYXQ6ICd7MH0nXG5cdCAgICAgICAgICAgIH0sXG5cdCAgICAgICAgICAgIGxpbmU6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1pbjogMCxcblx0ICAgICAgICB9LFxuXHQgICAgICAgIGNhdGVnb3J5QXhpczoge1xuXHQgICAgICAgICAgICBtYWpvckdyaWRMaW5lczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWFqb3JUaWNrczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGxhYmVsczoge1xuXHRcdFx0XHRcdHZpc2libGU6IGZhbHNlXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHRcdFx0dG9vbHRpcDoge1xuXHRcdFx0XHR2aXNpYmxlOiBmYWxzZSxcblx0ICAgICAgICB9XG5cdCAgICB9KS5kYXRhKCdrZW5kb0NoYXJ0Jyk7XG5cblx0XHR0aGlzLl93cml0dGVuRGF0YUNoYXJ0ID0gJCgnI3pubS13cml0dGVuRGF0YUNoYXJ0Jykua2VuZG9DaGFydCh7XG5cdFx0XHR0cmFuc2l0aW9uczogZmFsc2UsXG5cdFx0XHRjaGFydEFyZWE6IHtcblx0XHRcdFx0aGVpZ2h0OiAxMDBcblx0XHRcdH0sXG5cdCAgICAgICAgbGVnZW5kOiB7XG5cdCAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBzZXJpZXNEZWZhdWx0czoge1xuXHQgICAgICAgICAgICB0eXBlOiAnYmFyJyxcblx0ICAgICAgICAgICAgbGFiZWxzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxuXHQgICAgICAgICAgICAgICAgZm9ybWF0OiAnezB9Jyxcblx0ICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6ICd0cmFuc3BhcmVudCcsXG5cdFx0XHRcdFx0cG9zaXRpb246ICdpbnNpZGVCYXNlJyxcblx0XHRcdFx0XHR0ZW1wbGF0ZTogZ2V0V1JCeXRlc0xhYmVsVGVtcGxhdGUoKSxcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0Z2FwOiAuNSxcblx0XHRcdFx0c3BhY2luZzogMCxcblx0XHRcdFx0b3ZlcmxheToge1xuXHRcdFx0XHRcdGdyYWRpZW50OiAnbm9uZSdcblx0XHRcdFx0fSxcblx0XHRcdFx0Ym9yZGVyOiB7XG5cdFx0XHRcdFx0d2lkdGg6IDBcblx0XHRcdFx0fVxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzOiBbXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRuYW1lOiAnV3JpdHRlbiBkYXRhJyxcblx0XHQgICAgICAgICAgICBmaWVsZDogJ3ZhbHVlJyxcblx0XHQgICAgICAgICAgICBjYXRlZ29yeUZpZWxkOiAnY2F0ZWdvcnknLFxuXHRcdFx0XHRcdGNvbG9yOiAnI0ZCN0QzMydcblx0XHQgICAgICAgIH1cblx0XHRcdF0sXG5cdCAgICAgICAgdmFsdWVBeGlzOiB7XG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgZm9ybWF0OiAnezB9J1xuXHQgICAgICAgICAgICB9LFxuXHQgICAgICAgICAgICBsaW5lOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtaW46IDAsXG5cdCAgICAgICAgfSxcblx0ICAgICAgICBjYXRlZ29yeUF4aXM6IHtcblx0ICAgICAgICAgICAgbWFqb3JHcmlkTGluZXM6IHtcblx0ICAgICAgICAgICAgICAgIHZpc2libGU6IGZhbHNlXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdG1ham9yVGlja3M6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiBmYWxzZVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsYWJlbHM6IHtcblx0XHRcdFx0XHR2aXNpYmxlOiBmYWxzZVxuXHRcdFx0XHR9XG5cdCAgICAgICAgfSxcblx0XHRcdHRvb2x0aXA6IHtcblx0XHRcdFx0dmlzaWJsZTogZmFsc2UsXG5cdCAgICAgICAgfVxuXHQgICAgfSkuZGF0YSgna2VuZG9DaGFydCcpO1xuXG5cdFx0dGhpcy5fcmVhZERhdGFDaGFydCA9ICQoJyN6bm0tcmVhZERhdGFDaGFydCcpLmtlbmRvQ2hhcnQoe1xuXHRcdFx0dHJhbnNpdGlvbnM6IGZhbHNlLFxuXHRcdFx0Y2hhcnRBcmVhOiB7XG5cdFx0XHRcdGhlaWdodDogMTAwXG5cdFx0XHR9LFxuXHQgICAgICAgIGxlZ2VuZDoge1xuXHQgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgc2VyaWVzRGVmYXVsdHM6IHtcblx0ICAgICAgICAgICAgdHlwZTogJ2JhcicsXG5cdCAgICAgICAgICAgIGxhYmVsczoge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogdHJ1ZSxcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfScsXG5cdCAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kOiAndHJhbnNwYXJlbnQnLFxuXHRcdFx0XHRcdHBvc2l0aW9uOiAnaW5zaWRlQmFzZScsXG5cdFx0XHRcdFx0dGVtcGxhdGU6IGdldFdSQnl0ZXNMYWJlbFRlbXBsYXRlKCksXG5cdCAgICAgICAgICAgIH0sXG5cdFx0XHRcdGdhcDogLjUsXG5cdFx0XHRcdHNwYWNpbmc6IDAsXG5cdFx0XHRcdG92ZXJsYXk6IHtcblx0XHRcdFx0XHRncmFkaWVudDogJ25vbmUnXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGJvcmRlcjoge1xuXHRcdFx0XHRcdHdpZHRoOiAwXG5cdFx0XHRcdH1cblx0ICAgICAgICB9LFxuXHQgICAgICAgIHNlcmllczogW1xuXHRcdFx0XHR7XG5cdFx0XHRcdFx0bmFtZTogJ1JlYWQgZGF0YScsXG5cdFx0ICAgICAgICAgICAgZmllbGQ6ICd2YWx1ZScsXG5cdFx0ICAgICAgICAgICAgY2F0ZWdvcnlGaWVsZDogJ2NhdGVnb3J5Jyxcblx0XHRcdFx0XHRjb2xvcjogJyNGQjdEMzMnXG5cdFx0ICAgICAgICB9XG5cdFx0XHRdLFxuXHQgICAgICAgIHZhbHVlQXhpczoge1xuXHQgICAgICAgICAgICBsYWJlbHM6IHtcblx0ICAgICAgICAgICAgICAgIGZvcm1hdDogJ3swfSdcblx0ICAgICAgICAgICAgfSxcblx0ICAgICAgICAgICAgbGluZToge1xuXHQgICAgICAgICAgICAgICAgdmlzaWJsZTogZmFsc2Vcblx0ICAgICAgICAgICAgfSxcblx0XHRcdFx0bWluOiAwLFxuXHQgICAgICAgIH0sXG5cdCAgICAgICAgY2F0ZWdvcnlBeGlzOiB7XG5cdCAgICAgICAgICAgIG1ham9yR3JpZExpbmVzOiB7XG5cdCAgICAgICAgICAgICAgICB2aXNpYmxlOiBmYWxzZVxuXHQgICAgICAgICAgICB9LFxuXHRcdFx0XHRtYWpvclRpY2tzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fSxcblx0XHRcdFx0bGFiZWxzOiB7XG5cdFx0XHRcdFx0dmlzaWJsZTogZmFsc2Vcblx0XHRcdFx0fVxuXHQgICAgICAgIH0sXG5cdFx0XHR0b29sdGlwOiB7XG5cdFx0XHRcdHZpc2libGU6IGZhbHNlLFxuXHQgICAgICAgIH1cblx0ICAgIH0pLmRhdGEoJ2tlbmRvQ2hhcnQnKTtcblxuXHRcdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIHJlZHJhdyBhbGwgY2hhcnRzIGluIGNhc2Ugb2Ygd2luZG93IHJlc2l6ZVxuXHRcdCQod2luZG93KS5vbigncmVzaXplJywgJC5wcm94eSh0aGlzLl9vbldpbmRvd1Jlc2l6ZSwgdGhpcykpO1xuXHRcdHRoaXMuX29uV2luZG93UmVzaXplKCk7IC8vIEFsc28gZG8gaXQgaW1tZWRpYXRlbHlcblxuXHRcdC8vIFJlcXVlc3QgZGF0YSB0byBzZXJ2ZXJcblx0XHR0aGlzLl9yZXF1ZXN0RGF0YSh0cnVlKTtcblx0fVxuXG5cdGRlc3Ryb3koKVxuXHR7XG5cdFx0Ly8gQ2FsbCBzdXBlciBtZXRob2Rcblx0XHRzdXBlci5kZXN0cm95KCk7XG5cblx0XHQvLyBDbG9zZSBtb25pdG9yaW5nXG5cdFx0dGhpcy5fb25DbG9zZU1vbml0b3JCdENsaWNrKCk7XG5cblx0XHQvLyBSZW1vdmUgZG91YmxlY2xpY2sgZXZlbnQgbGlzdGVuZXJzXG5cdFx0dGhpcy5fem9uZUxpc3RCb3gud3JhcHBlci5maW5kKCcuay1saXN0Jykub2ZmKCdkYmxjbGljaycpO1xuXHRcdHRoaXMuX3Jvb21MaXN0Qm94LndyYXBwZXIuZmluZCgnLmstbGlzdCcpLm9mZignZGJsY2xpY2snKTtcblx0XHR0aGlzLl91c2VyTGlzdEJveC53cmFwcGVyLmZpbmQoJy5rLWxpc3QnKS5vZmYoJ2RibGNsaWNrJyk7XG5cblx0XHQvLyBSZW1vdmUgb3RoZXIgZXZlbnQgbGlzdGVuZXJzXG5cdFx0JCgnI3pubS1jcmVhdGVSb29tQnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3pubS1yZW1vdmVSb29tQnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3pubS1yb29tQ3JlYXRvckNyZWF0ZUJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyN6bm0tZmlsdGVyUm9vbUJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyN6bm0tYXBwbHlSb29tRmlsdGVyQ0InKS5vZmYoJ2NoYW5nZScpO1xuXHRcdCQoJyN6bm0tZmlsdGVyVXNlckJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyN6bm0tYXBwbHlVc2VyRmlsdGVyQ0InKS5vZmYoJ2NoYW5nZScpO1xuXHRcdCQoJyN6bm0tbW9uaXRvckJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyN6bm0tc2VuZE1lc3NhZ2VCdCcpLm9mZignY2xpY2snKTtcblx0XHQkKCcjem5tLW1lc3NhZ2VJbicpLm9mZigna2V5dXAnKTtcblx0XHQkKCcjem5tLWNsb3NlTW9uaXRvckJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyN6bm0tZWRpdEJ0Jykub2ZmKCdjbGljaycpO1xuXHRcdCQoJyN6bm0tY2FuY2VsQnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3pubS1zdWJtaXRCdCcpLm9mZignY2xpY2snKTtcblx0XHQkKHdpbmRvdykub2ZmKCdyZXNpemUnKTtcblx0XHQkKCcjem5tLXJlbG9hZFdvcmRzQnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3pubS1yZWxvYWRab25lRXh0QnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3pubS1kaXNjb25uZWN0QnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3pubS1raWNrQnQnKS5vZmYoJ2NsaWNrJyk7XG5cdFx0JCgnI3pubS1iYW5CdCcpLm9mZignY2xpY2snKTtcblxuXHRcdC8vIENsZWFyIHJlcXVlc3Qgc2NoZWR1bGluZ1xuXHRcdGNsZWFyVGltZW91dCh0aGlzLl9yZXF1ZXN0VGltZXIpO1xuXG5cdFx0Ly8gSGlkZSByb29tIGNyZWF0aW9uIHBhbmVsXG5cdFx0JCgnI3pubS1jcmVhdGVSb29tTW9kYWwnKS5tb2RhbCgnaGlkZScpO1xuXG5cdFx0Ly8gUmVtb3ZlIHJvb20gY3JlYXRpb24gcGFuZWwgbGlzdGVuZXJcblx0XHQkKCcjem5tLWNyZWF0ZVJvb21Nb2RhbCcpLm9mZignaGlkZGVuLmJzLm1vZGFsJyk7XG5cblx0XHQvLyBSZW1vdmUgZmlsdGVyIHBhbmVscyBsaXN0ZW5lcnNcblx0XHQkKHRoaXMuX3Jvb21GaWx0ZXIpLm9mZih0aGlzLl9yb29tRmlsdGVyLkVYUFJFU1NJT05fVVBEQVRFRF9FVkVOVCk7XG5cdFx0JCh0aGlzLl91c2VyRmlsdGVyKS5vZmYodGhpcy5fdXNlckZpbHRlci5FWFBSRVNTSU9OX1VQREFURURfRVZFTlQpO1xuXHR9XG5cblx0b25FeHRlbnNpb25Db21tYW5kKGNvbW1hbmQsIGRhdGEpXG5cdHtcblx0XHQvLyBEYXRhIHJlY2VpdmVkXG5cdFx0aWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX0RBVEEpXG5cdFx0e1xuXHRcdFx0Ly8gV2UgaGF2ZSB0byBjaGVjayBpZiB0aGUgcmVzcG9uc2UgaWQgY29ycmVzcG9uZHMgdG8gdGhlIGN1cnJlbnQgcmVxdWVzdCBpZDtcblx0XHRcdC8vIGlmIG5vdCwgdGhlIHJlc3BvbnNlIGlzIGRpc2NhcmRlZCBhcyBpdCByZWZlcnMgdG8gYW4gb3V0ZGF0ZXQgcmVxdWVzdFxuXHRcdFx0Y29uc3QgcmVzcG9uc2VJZCA9IGRhdGEuZ2V0SW50KCdpZCcpO1xuXG5cdFx0XHRpZiAocmVzcG9uc2VJZCA9PSB0aGlzLl9jdXJyZW50UmVxdWVzdElkKVxuXHRcdFx0e1xuXHRcdFx0XHQvLyAtLS0gWk9ORVMgTElTVCAtLS1cblx0XHRcdFx0aWYgKGRhdGEuY29udGFpbnNLZXkoJ3pvbmVzJykpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHR0aGlzLl9zZXRab25lc0RhdGFQcm92aWRlcihkYXRhLmdldFNGU0FycmF5KCd6b25lcycpKTtcblxuXHRcdFx0XHRcdGlmICh0aGlzLl9zZWxlY3RlZFpvbmUpXG5cdFx0XHRcdFx0XHR0aGlzLl9zZXRTY29wZUxhYmVsKCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyAtLS0gUk9PTVMgTElTVCAtLS1cblx0XHRcdFx0aWYgKGRhdGEuY29udGFpbnNLZXkoJ3Jvb21zJykpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHR0aGlzLl9zZXRHcm91cHNEYXRhUHJvdmlkZXIoZGF0YS5nZXRVdGZTdHJpbmdBcnJheSgnZ3JvdXBzJykpO1xuXG5cdFx0XHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0XHRcdFx0Ly8gSWYgYSBudWxsIHJvb21zIGxpc3QgaXMgcmV0dXJuZWQsIHRoZSB6b25lIG11c3QgaGF2ZSBiZWVuIGRlbGV0ZWQhXG5cdFx0XHRcdFx0aWYgKCFkYXRhLmlzTnVsbCgncm9vbXMnKSlcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHR0aGlzLl9zZXRSb29tc0RhdGFQcm92aWRlcihkYXRhLmdldFNGU0FycmF5KCdyb29tcycpKTtcblxuXHRcdFx0XHRcdFx0aWYgKCF0aGlzLl9zZWxlY3RlZFJvb20pXG5cdFx0XHRcdFx0XHRcdHRoaXMuX3NldFNjb3BlTGFiZWwoKTtcblxuXHRcdFx0XHRcdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0XHRcdFx0XHQvLyBTaG93IHdhcm5pbmcgaWYgdGhlIHJvb21zIGxpc3QgZXhjZWVkcyB0aGUgc2VydmVyLXNpZGUgbGltaXRcblx0XHRcdFx0XHRcdGlmIChkYXRhLmNvbnRhaW5zS2V5KCdyU2l6ZScpKVxuXHRcdFx0XHRcdFx0XHR0aGlzLl9zaG93TGltaXRFeGNlZWRlZFdhcm5pbmcoJCgnI3pubS1yb29tTGlzdFdhcm5pbmcnKSwgJ1RoZSByZWNlaXZlZCBsaXN0IGlzIGluY29tcGxldGUsIGJlY2F1c2UgaXRzIHNpemUgKCcgKyBkYXRhLmdldEludCgnclNpemUnKSArICcgUm9vbXMpIGV4Y2VlZGVkIHRoaXMgY2xpZW50XFwncyBsaW1pdCBvZiAnICsgZGF0YS5nZXRJbnQoJ3JMaW1pdCcpICsgJzsgeW91IHNob3VsZCByZWZpbmUgeW91ciBzZWFyY2gnKTtcblx0XHRcdFx0XHRcdGVsc2Vcblx0XHRcdFx0XHRcdFx0dGhpcy5fc2hvd0xpbWl0RXhjZWVkZWRXYXJuaW5nKCQoJyN6bm0tcm9vbUxpc3RXYXJuaW5nJyksICcnKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdGlmICh0aGlzLl9hY3RpdmVQYW5lbFR5cGUgPT0gJ3Jvb20nKVxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHR0aGlzLl9hY2NvcmRpb24uc2VsZWN0KCdbZGF0YS1pdGVtLXR5cGU9XCJ6b25lXCJdJyk7XG5cdFx0XHRcdFx0XHRcdHRoaXMuX2FjY29yZGlvbi5leHBhbmQoJ1tkYXRhLWl0ZW0tdHlwZT1cInpvbmVcIl0nKTtcblx0XHRcdFx0XHRcdFx0dGhpcy5fb25ab25lU2VsZWN0ZWQoKTtcblx0XHRcdFx0XHRcdFx0dGhpcy5fb25FbnRpdGllc1BhbmVsQ2hhbmdlKCk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gLS0tIFVTRVJTIExJU1QgLS0tXG5cdFx0XHRcdGlmIChkYXRhLmNvbnRhaW5zS2V5KCd1c2VycycpKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0Ly8gSWYgYSBudWxsIHVzZXJzIGxpc3QgaXMgcmV0dXJuZWQsIHRoZSByb29tIG11c3QgaGF2ZSBiZWVuIGRlbGV0ZWQhXG5cdFx0XHRcdFx0aWYgKCFkYXRhLmlzTnVsbCgndXNlcnMnKSlcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHR0aGlzLl9zZXRVc2Vyc0RhdGFQcm92aWRlcihkYXRhLmdldFNGU0FycmF5KCd1c2VycycpKTtcblxuXHRcdFx0XHRcdFx0Ly8gU2hvdyB3YXJuaW5nIGlmIHRoZSB1c2VycyBsaXN0IGV4Y2VlZHMgdGhlIHNlcnZlci1zaWRlIGxpbWl0XG5cdFx0XHRcdFx0XHRpZiAoZGF0YS5jb250YWluc0tleSgndVNpemUnKSlcblx0XHRcdFx0XHRcdFx0dGhpcy5fc2hvd0xpbWl0RXhjZWVkZWRXYXJuaW5nKCQoJyN6bm0tdXNlckxpc3RXYXJuaW5nJyksICdUaGUgcmVjZWl2ZWQgbGlzdCBpcyBpbmNvbXBsZXRlLCBiZWNhdXNlIGl0cyBzaXplICgnICsgZGF0YS5nZXRJbnQoJ3VTaXplJykgKyAnIHVzZXJzKSBleGNlZWRzIHRoaXMgY2xpZW50XFwncyBsaW1pdCBvZiAnICsgZGF0YS5nZXRJbnQoJ3VMaW1pdCcpICsgJzsgeW91IHNob3VsZCByZWZpbmUgeW91ciBzZWFyY2gnKTtcblx0XHRcdFx0XHRcdGVsc2Vcblx0XHRcdFx0XHRcdFx0dGhpcy5fc2hvd0xpbWl0RXhjZWVkZWRXYXJuaW5nKCQoJyN6bm0tdXNlckxpc3RXYXJuaW5nJyksICcnKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdGlmICh0aGlzLl9hY3RpdmVQYW5lbFR5cGUgPT0gJ3VzZXInKVxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHR0aGlzLl9hY2NvcmRpb24uc2VsZWN0KCdbZGF0YS1pdGVtLXR5cGU9XCJyb29tXCJdJyk7XG5cdFx0XHRcdFx0XHRcdHRoaXMuX2FjY29yZGlvbi5leHBhbmQoJ1tkYXRhLWl0ZW0tdHlwZT1cInJvb21cIl0nKTtcblx0XHRcdFx0XHRcdFx0dGhpcy5fb25Sb29tU2VsZWN0ZWQoKTtcblx0XHRcdFx0XHRcdFx0dGhpcy5fb25FbnRpdGllc1BhbmVsQ2hhbmdlKCk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gLS0tIE1PTklUT1JFRCBEQVRBIC0tLVxuXHRcdFx0XHRpZiAoZGF0YS5jb250YWluc0tleSgnbW9uaXRvcmVkJykpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRjb25zdCB6b25lID0gZGF0YS5nZXRTRlNPYmplY3QoJ21vbml0b3JlZCcpLmdldFV0ZlN0cmluZygnem9uZScpO1xuXHRcdFx0XHRcdGNvbnN0IHR5cGUgPSBkYXRhLmdldFNGU09iamVjdCgnbW9uaXRvcmVkJykuZ2V0VXRmU3RyaW5nKCd0eXBlJyk7XG5cdFx0XHRcdFx0Y29uc3QgbmFtZSA9IGRhdGEuZ2V0U0ZTT2JqZWN0KCdtb25pdG9yZWQnKS5nZXRVdGZTdHJpbmcoJ25hbWUnKTtcblxuXHRcdFx0XHRcdGlmICh6b25lID09IHRoaXMuX21vbml0b3JlZFpvbmUgJiYgdHlwZSA9PSB0aGlzLl9tb25pdG9yZWRUeXBlICYmIG5hbWUgPT0gdGhpcy5fbW9uaXRvcmVkTmFtZSlcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRpZiAoIWRhdGEuZ2V0U0ZTT2JqZWN0KCdtb25pdG9yZWQnKS5pc051bGwoJ3BhcmFtcycpKVxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHRjb25zdCBwYXJhbXMgPSBkYXRhLmdldFNGU09iamVjdCgnbW9uaXRvcmVkJykuZ2V0U0ZTQXJyYXkoJ3BhcmFtcycpO1xuXG5cdFx0XHRcdFx0XHRcdHRoaXMuX3NldE1vbml0b3JpbmdJbnRlcmZhY2UoKTtcblxuXHRcdFx0XHRcdFx0XHQvLyBCdWlsZCBpbnRlcmZhY2Vcblx0XHRcdFx0XHRcdFx0aWYgKCF0aGlzLl9pc0VkaXRpbmcpXG5cdFx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLl9pbnRlcmZhY2VCdWlsZGVyLmJ1aWxkSW50ZXJmYWNlKHBhcmFtcywgYHpubS0ke3RoaXMuX21vbml0b3JlZFR5cGV9VGFiTmF2aWdhdG9yYCwgdHJ1ZSk7XG5cblx0XHRcdFx0XHRcdFx0XHRpZiAoIXRoaXMuX3NraXBJbml0VGFicylcblx0XHRcdFx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRcdFx0XHQkKGAjem5tLSR7dGhpcy5fbW9uaXRvcmVkVHlwZX1UYWJOYXZpZ2F0b3IgI3RhYnNgKS5zY3JvbGxpbmdUYWJzKHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0Ym9vdHN0cmFwVmVyc2lvbjogNCxcblx0XHRcdFx0XHRcdFx0XHRcdFx0c2Nyb2xsVG9UYWJFZGdlOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRlbmFibGVTd2lwaW5nOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRkaXNhYmxlU2Nyb2xsQXJyb3dzT25GdWxseVNjcm9sbGVkOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRjc3NDbGFzc0xlZnRBcnJvdzogJ2ZhIGZhLWNoZXZyb24tbGVmdCcsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNzc0NsYXNzUmlnaHRBcnJvdzogJ2ZhIGZhLWNoZXZyb24tcmlnaHQnXG5cdFx0XHRcdFx0XHRcdFx0XHR9KTtcblxuXHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5fc2tpcEluaXRUYWJzID0gdHJ1ZTtcblxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gU2V0IGZpcnN0IHRhYiBwYW5lbCBhcyBhY3RpdmVcblx0XHRcdFx0XHRcdFx0XHRcdHRoaXMuX2ludGVyZmFjZUJ1aWxkZXIuYWN0aXZhdGVGaXJzdFRhYlBhbmVsKCk7XG5cblx0XHRcdFx0XHRcdFx0XHRcdC8vIFJlZHJhdyB0aW1lIHJhbmdlIHNsaWRlciB0byBzZXQgaXRzIHdpZHRoXG5cdFx0XHRcdFx0XHRcdFx0XHR0aGlzLl90aW1lU2xpZGVyLnJlc2l6ZSgpO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBBZGQgbGlzdGVuZXIgdG8gcmVkcmF3IGFsbCBjaGFydHMgb24gdGFiIGNoYW5nZVxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gKHRvIHdvcmsgYXJvdW5kIGFuIGlzc3VlIHdpdGggdGhlIGNoYXJ0IHJlc2l6aW5nIHRvIGRlZmF1bHQgd2lkdGggd2hlbiBwYW5lIGlzIGhpZGRlbilcblx0XHRcdFx0XHRcdFx0XHRcdCQoJ2FbZGF0YS10b2dnbGU9XCJ0YWJcIl0nKS5vbignc2hvd24uYnMudGFiJywgJC5wcm94eSh0aGlzLl9vbldpbmRvd1Jlc2l6ZSwgdGhpcykpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdC8vIERpc2FibGUgY2F0ZWdvcmllc1xuXHRcdFx0XHRcdFx0XHRsZXQgZGlzYWJsZWRDYXQgPSAoZGF0YS5nZXRTRlNPYmplY3QoJ21vbml0b3JlZCcpLmNvbnRhaW5zS2V5KCdleGNsdWRlJykgPyBkYXRhLmdldFNGU09iamVjdCgnbW9uaXRvcmVkJykuZ2V0VXRmU3RyaW5nQXJyYXkoJ2V4Y2x1ZGUnKSA6IFtdKTtcblxuXHRcdFx0XHRcdFx0XHRmb3IgKGxldCBjYXQgb2YgZGlzYWJsZWRDYXQpXG5cdFx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0XHRsZXQgbmF2TGluayA9ICQoYCN6bm0tJHt0aGlzLl9tb25pdG9yZWRUeXBlfVRhYk5hdmlnYXRvciAjdGFicyAjdGFiLSR7Y2F0fWApO1xuXG5cdFx0XHRcdFx0XHRcdFx0bmF2TGluay5hZGRDbGFzcygnZGlzYWJsZWQnKTtcblx0XHRcdFx0XHRcdFx0XHRuYXZMaW5rLmF0dHIoJ3RhYmluZGV4JywgLTEpO1xuXHRcdFx0XHRcdFx0XHRcdG5hdkxpbmsuYXR0cignYXJpYS1kaXNhYmxlZCcsIHRydWUpO1xuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0aWYgKHRoaXMuX21vbml0b3JlZFR5cGUgPT0gdGhpcy5NT05JVE9SRURfVFlQRV9aT05FKVxuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX3Nob3dab25lVHJhZmZpY0RhdGEoZGF0YS5nZXRTRlNPYmplY3QoJ21vbml0b3JlZCcpLmdldFNGU09iamVjdCgndHJhZmZpYycpKTtcblxuXHRcdFx0XHRcdFx0XHRpZiAodGhpcy5fbW9uaXRvcmVkVHlwZSA9PSB0aGlzLk1PTklUT1JFRF9UWVBFX1VTRVIpXG5cdFx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0XHQvLyBTdGF0c1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX3Nob3dVc2VyU3RhdHNEYXRhKGRhdGEuZ2V0U0ZTT2JqZWN0KCdtb25pdG9yZWQnKS5nZXRTRlNPYmplY3QoJ3N0YXRzJykpO1xuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gTlBDXG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgaXNOcGMgPSBkYXRhLmdldFNGU09iamVjdCgnbW9uaXRvcmVkJykuZ2V0Qm9vbCgnbnBjJyk7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBEaXNhYmxlIGRpc2Nvbm5lY3QsIGtpY2sgYW5kIGJhbiBidXR0b25zXG5cdFx0XHRcdFx0XHRcdFx0JCgnI3pubS1kaXNjb25uZWN0QnQnKS5hdHRyKCdkaXNhYmxlZCcsIGlzTnBjKTtcblx0XHRcdFx0XHRcdFx0XHQkKCcjem5tLWtpY2tCdCcpLmF0dHIoJ2Rpc2FibGVkJywgaXNOcGMpO1xuXHRcdFx0XHRcdFx0XHRcdCQoJyN6bm0tYmFuQnQnKS5hdHRyKCdkaXNhYmxlZCcsIGlzTnBjKTtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIEdlby1sb2NhdGlvblxuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IGdlb0xvY0RhdGEgPSBkYXRhLmdldFNGU09iamVjdCgnbW9uaXRvcmVkJykuZ2V0U0ZTT2JqZWN0KCdnZW9Mb2MnKTtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLl9zZXRHZW9Mb2NhdGlvblVJKGdlb0xvY0RhdGEpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRcdC8vIFNob3cgYWxlcnRcblx0XHRcdFx0XHRcdFx0dGhpcy5zaGVsbEN0cmwuc2hvd1NpbXBsZUFsZXJ0KGBUaGUgJHtjYXBpdGFsaXplRmlyc3QodGhpcy5fbW9uaXRvcmVkVHlwZSl9IGJlaW5nIG1vbml0b3JlZCBpcyBubyBtb3JlIGF2YWlsYWJsZSBvbiB0aGUgc2VydmVyLCBwbGVhc2Ugc2VsZWN0IGFub3RoZXIgb25lLmAsIGZhbHNlKTtcblxuXHRcdFx0XHRcdFx0XHQvLyBDYW5jZWwgbW9uaXRvcmluZ1xuXHRcdFx0XHRcdFx0XHR0aGlzLl9vbkNsb3NlTW9uaXRvckJ0Q2xpY2soKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRlbHNlIGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9VUERBVEVfRVJST1IpXG5cdFx0e1xuXHRcdFx0aWYgKGRhdGEuZ2V0VXRmU3RyaW5nKCd6b25lJykgPT0gdGhpcy5fbW9uaXRvcmVkWm9uZVxuXHRcdFx0XHQmJiBkYXRhLmdldFV0ZlN0cmluZygndHlwZScpID09ICB0aGlzLl9tb25pdG9yZWRUeXBlXG5cdFx0XHRcdCYmIGRhdGEuZ2V0VXRmU3RyaW5nKCduYW1lJykgPT0gIHRoaXMuX21vbml0b3JlZE5hbWUpXG5cdFx0XHR7XG5cdFx0XHRcdC8vIFNob3cgYWxlcnRcblx0XHRcdFx0dGhpcy5zaGVsbEN0cmwuc2hvd1NpbXBsZUFsZXJ0KGBVbmFibGUgdG8gdXBkYXRlICR7Y2FwaXRhbGl6ZUZpcnN0KHRoaXMuX21vbml0b3JlZFR5cGUpfSBzZXR0aW5nczsgdGhlIGZvbGxvd2luZyBlcnJvciB3YXMgcmVwb3J0ZWQ6ICR7ZGF0YS5nZXRVdGZTdHJpbmcoJ21lc3NhZ2UnKX0uYCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfUk9PTV9DT05GSUcpXG5cdFx0e1xuXHRcdFx0Ly8gUmUtZW5hYmxlIENyZWF0ZSBidXR0b25cblx0XHRcdCQoJyN6bm0tY3JlYXRlUm9vbUJ0JykuYXR0cignZGlzYWJsZWQnLCBmYWxzZSk7XG5cblx0XHRcdC8vIFNob3cgUm9vbSBjcmVhdGlvbiBwYW5lbFxuXHRcdFx0dGhpcy5fc2hvd1Jvb21DcmVhdGlvblBhbmVsKGRhdGEuZ2V0U0ZTQXJyYXkoJ3NldHRpbmdzJykpO1xuXHRcdH1cblxuXHRcdGVsc2UgaWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX1JPT01fQ09ORklHX0VSUk9SKVxuXHRcdHtcblx0XHRcdC8vIFJlLWVuYWJsZSBDcmVhdGUgYnV0dG9uXG5cdFx0XHQkKCcjem5tLWNyZWF0ZVJvb21CdCcpLmF0dHIoJ2Rpc2FibGVkJywgZmFsc2UpO1xuXG5cdFx0XHQvLyBTaG93IGFuIGFsZXJ0XG5cdFx0XHR0aGlzLnNoZWxsQ3RybC5zaG93U2ltcGxlQWxlcnQoZGF0YS5nZXRVdGZTdHJpbmcoJ2Vycm9yJykpO1xuXHRcdH1cblxuXHRcdGVsc2UgaWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX1JPT01fQ1JFQVRFRClcblx0XHR7XG5cdFx0XHQvLyBSZS1lbmFibGUgcm9vbSBjcmVhdGlvbiBwYW5lbFxuXHRcdFx0dGhpcy5fZW5hYmxlQ3JlYXRlUm9vbVBhbmVsKHRydWUpO1xuXG5cdFx0XHQvLyBIaWRlIHJvb20gY3JlYXRpb24gcGFuZWxcblx0XHRcdCQoJyN6bm0tY3JlYXRlUm9vbU1vZGFsJykubW9kYWwoJ2hpZGUnKTtcblxuXHRcdFx0Ly8gVXBkYXRlIHJvb21zIGxpc3Rcblx0XHRcdHRoaXMuX3JlcXVlc3REYXRhKHRydWUpO1xuXHRcdH1cblxuXHRcdGVsc2UgaWYgKGNvbW1hbmQgPT0gdGhpcy5SRVNQX1JPT01fQ1JFQVRJT05fRVJST1IpXG5cdFx0e1xuXHRcdFx0Ly8gRGlzcGxheSBlcnJvciBtZXNzYWdlXG5cdFx0XHQkKCcjem5tLWNyZWF0ZVJvb21FcnJvcicpLnRleHQoZGF0YS5nZXRVdGZTdHJpbmcoJ2Vycm9yJykpO1xuXHRcdFx0JCgnI3pubS1jcmVhdGVSb29tRXJyb3InKS5zaG93KCk7XG5cblx0XHRcdC8vIFJlLWVuYWJsZSByb29tIGNyZWF0aW9uIHBhbmVsXG5cdFx0XHR0aGlzLl9lbmFibGVDcmVhdGVSb29tUGFuZWwodHJ1ZSk7XG5cdFx0fVxuXG5cdFx0Ly8gVW5leHBlY3RlZCBlcnJvciByZWNlaXZlZFxuXHRcdC8vIFRoaXMgZXJyb3IgaXMgcmV0dXJuZWQgaW4gY2FzZSBzb21ldGhpbmcgd2VudCB3cm9uZyB3aGVuIHJldHJpZXZpbmcgdGhlIG1vbml0b3JlZCBlbnRpdHkgcGFyYW1ldGVycyxcblx0XHQvLyBzbyB3ZSBoYXZlIHRvIHN0b3AgcmVxdWVzdGluZyB0aGUgc2FtZSBlbnRpdHlcblx0XHRlbHNlIGlmIChjb21tYW5kID09IHRoaXMuUkVTUF9VTkVYUEVDVEVEX0VSUk9SKVxuXHRcdHtcblx0XHRcdC8vIENhbmNlbCBtb25pdG9yaW5nXG5cdFx0XHR0aGlzLl9vbkNsb3NlTW9uaXRvckJ0Q2xpY2soKTtcblxuXHRcdFx0Ly8gU2hvdyBhbiBhbGVydFxuXHRcdFx0dGhpcy5zaGVsbEN0cmwuc2hvd1NpbXBsZUFsZXJ0KGRhdGEuZ2V0VXRmU3RyaW5nKCdlcnJvcicpKTtcblx0XHR9XG5cblx0XHQvLyBFeHRlbnNpb24gKFpvbmUgb3IgUm9vbSkgbG9nIG1lc3NhZ2VzIHJlY2VpdmVkXG5cdFx0ZWxzZSBpZiAoY29tbWFuZCA9PSB0aGlzLlJFU1BfTE9HX01FU1NBR0VTKVxuXHRcdHtcblx0XHRcdGxldCBsb2dFbnRyaWVzID0gZGF0YS5nZXRTRlNBcnJheSgnZW50cmllcycpO1xuXG5cdFx0XHRmb3IgKGxldCBlID0gMDsgZSA8IGxvZ0VudHJpZXMuc2l6ZSgpOyBlKyspXG5cdFx0XHR7XG5cdFx0XHRcdGxldCBsb2dFbnRyeSA9IGxvZ0VudHJpZXMuZ2V0U0ZTT2JqZWN0KGUpO1xuXG5cdFx0XHRcdGNvbnN0IGxvZ1pvbmUgPSBsb2dFbnRyeS5nZXRVdGZTdHJpbmcoJ3pvbmUnKTtcblx0XHRcdFx0Y29uc3QgbG9nUm9vbSA9IGxvZ0VudHJ5LmdldFV0ZlN0cmluZygncm9vbScpO1xuXG5cdFx0XHRcdC8vIENoZWNrIGlmIHRoZSB6b25lIGlzIGN1cnJlbnRseSBtb25pdG9yZWRcblx0XHRcdFx0aWYgKHRoaXMuX21vbml0b3JlZFpvbmUgPT0gbG9nWm9uZSlcblx0XHRcdFx0e1xuXHRcdFx0XHRcdC8vIGNvbnNvbGUubG9nKGxvZ0VudHJ5LmdldExvbmcoJ3RpbWUnKSlcblx0XHRcdFx0XHQvLyBjb25zb2xlLmxvZyhuZXcgRGF0ZShsb2dFbnRyeS5nZXRMb25nKCd0aW1lJykpXG5cblx0XHRcdFx0XHRsZXQgZWxlID0ge1xuXHRcdFx0XHRcdFx0dGltZXN0YW1wOiBrZW5kby50b1N0cmluZyhuZXcgRGF0ZShsb2dFbnRyeS5nZXRMb25nKCd0aW1lJykpLCAnZGQvTU0veXl5eSBISDptbTpzcycpLFxuXHRcdFx0XHRcdFx0bGV2ZWw6IGxvZ0VudHJ5LmdldFV0ZlN0cmluZygnbGV2ZWwnKSxcblx0XHRcdFx0XHRcdG1lc3NhZ2U6IGxvZ0VudHJ5LmdldFV0ZlN0cmluZygnbXNnJyksXG5cdFx0XHRcdFx0fTtcblxuXHRcdFx0XHRcdGlmICh0aGlzLl9tb25pdG9yZWRUeXBlID09IHRoaXMuTU9OSVRPUkVEX1RZUEVfWk9ORSAmJiBsb2dSb29tID09ICcnKVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdC8vIEFkZCB0byB6b25lIGV4dGVuc2lvbiBsb2dcblx0XHRcdFx0XHRcdHRoaXMuX2FkZExvZ0VudHJ5VG9HcmlkKHRoaXMuX3pvbmVFeHRMb2dHcmlkLCBlbGUpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0aWYgKHRoaXMuX21vbml0b3JlZFR5cGUgPT0gdGhpcy5NT05JVE9SRURfVFlQRV9ST09NICYmIHRoaXMuX21vbml0b3JlZE5hbWUgPT0gbG9nUm9vbSlcblx0XHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdFx0Ly8gQWRkIHRvIHJvb20gZXh0ZW5zaW9uIGxvZ1xuXHRcdFx0XHRcdFx0XHR0aGlzLl9hZGRMb2dFbnRyeVRvR3JpZCh0aGlzLl9yb29tRXh0TG9nR3JpZCwgZWxlKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBVSSBFVkVOVCBMSVNURU5FUlNcblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRfb25VcGRhdGVJbnRlcnZhbENoYW5nZSgpXG5cdHtcblx0XHQvLyBSZXF1ZXN0IGRhdGEgdG8gc2VydmVyXG5cdFx0dGhpcy5fcmVxdWVzdERhdGEoZmFsc2UpO1xuXHR9XG5cblx0X29uRW50aXRpZXNQYW5lbENoYW5nZSgpXG5cdHtcblx0XHQvLyBTZXQgbWFpbiBjb250cm9scyBzdGF0ZVxuXHRcdHRoaXMuX3NldE1haW5Db250cm9sc0VuYWJsZWQoKTtcblxuXHRcdC8vIFJlcXVlc3QgZGF0YSB0byBzZXJ2ZXJcblx0XHR0aGlzLl9yZXF1ZXN0RGF0YSh0cnVlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgdGhlIFNjb3BlIGxhYmVsIGluIHRoZSBSb29tcyBwYW5lbC5cblx0ICovXG5cdF9vblpvbmVTZWxlY3RlZCgpXG5cdHtcblx0XHQvLyBDbGVhciBSb29tIGFuZCBVc2VyIGxpc3RzXG5cdFx0dGhpcy5fcmVzZXRSb29tTGlzdCgpO1xuXHRcdHRoaXMuX3Jlc2V0VXNlckxpc3QoKTtcblxuXHRcdC8vIFNldCBzY29wZSBsYWJlbFxuXHRcdHRoaXMuX3NldFNjb3BlTGFiZWwoKTtcblxuXHRcdC8vIEVuYWJsZS9kaXNhYmxlIFJvb20gYW5kIFVzZXIgdG9vbHNcblx0XHRjb25zdCBkaXNhYmxlZCA9IHRoaXMuX3NlbGVjdGVkWm9uZSA9PSB1bmRlZmluZWQ7XG5cblx0XHQvLyAoTk9URTogdGhpcyBlbmFibGVzL2Rpc2FibGVzIHdob2xlIGZpZWxkc2V0OyB0aGlzIGRvZXNuJ3QgYWZmZWN0IEtlbmRvIERyb3BEb3duLCBzbyB3ZSBoYXZlIHRvIGRvIGl0IG1hbnVhbGx5KVxuXHRcdCQoJyNyb29tVG9vbHMnKS5hdHRyKCdkaXNhYmxlZCcsIGRpc2FibGVkKTtcblx0XHQkKCcjdXNlclRvb2xzJykuYXR0cignZGlzYWJsZWQnLCBkaXNhYmxlZCk7XG5cblx0XHR0aGlzLl9ncm91cHNEcm9wRG93bi5lbmFibGUoIWRpc2FibGVkKTtcblxuXHRcdC8vIFNldCBtYWluIGNvbnRyb2xzIHN0YXRlXG5cdFx0dGhpcy5fc2V0TWFpbkNvbnRyb2xzRW5hYmxlZCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFVwZGF0ZSB0aGUgU2NvcGUgbGFiZWwgaW4gdGhlIFVzZXJzIHBhbmVsLlxuXHQgKi9cblx0X29uUm9vbVNlbGVjdGVkKClcblx0e1xuXHRcdC8vIENsZWFyIFVzZXIgbGlzdFxuXHRcdHRoaXMuX3Jlc2V0VXNlckxpc3QoKTtcblxuXHRcdC8vIFNldCBzY29wZSBsYWJlbFxuXHRcdHRoaXMuX3NldFNjb3BlTGFiZWwoKTtcblxuXHRcdC8vIEVuYWJsZSBSZW1vdmUgYnV0dG9uXG5cdFx0JCgnI3pubS1yZW1vdmVSb29tQnQnKS5hdHRyKCdkaXNhYmxlZCcsIHRoaXMuX3NlbGVjdGVkUm9vbSA9PSB1bmRlZmluZWQpO1xuXG5cdFx0Ly8gU2V0IG1haW4gY29udHJvbHMgc3RhdGVcblx0XHR0aGlzLl9zZXRNYWluQ29udHJvbHNFbmFibGVkKCk7XG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlIHRoZSBzY29wZSBsYWJlbCBpbiB0aGUgVXNlcnMgcGFuZWwuXG5cdCAqL1xuXHRfb25Hcm91cENoYW5nZSgpXG5cdHtcblx0XHQvLyBDbGVhciBSb29tIGFuZCBVc2VyIGxpc3RzXG5cdFx0dGhpcy5fcmVzZXRSb29tTGlzdCgpO1xuXHRcdHRoaXMuX3Jlc2V0VXNlckxpc3QoKTtcblxuXHRcdC8vIFNldCBzY29wZSBsYWJlbFxuXHRcdHRoaXMuX3NldFNjb3BlTGFiZWwoKTtcblxuXHRcdC8vIFJlcXVlc3QgZGF0YSB0byBzZXJ2ZXJcblx0XHR0aGlzLl9yZXF1ZXN0RGF0YSh0cnVlKTtcblxuXHRcdC8vIFNldCBtYWluIGNvbnRyb2xzIHN0YXRlXG5cdFx0dGhpcy5fc2V0TWFpbkNvbnRyb2xzRW5hYmxlZCgpO1xuXHR9XG5cblx0X29uVXNlclNlbGVjdGVkKClcblx0e1xuXHRcdC8vIFNldCBtYWluIGNvbnRyb2xzIHN0YXRlXG5cdFx0dGhpcy5fc2V0TWFpbkNvbnRyb2xzRW5hYmxlZCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNob3cgcm9vbSBjcmVhdGlvbiBwYW5lbC5cblx0ICovXG5cdF9vbkNyZWF0ZVJvb21CdENsaWNrKClcblx0e1xuXHRcdC8vIERpc2FibGUgQ3JlYXRlIGJ1dHRvblxuXHRcdCQoJyN6bm0tY3JlYXRlUm9vbUJ0JykuYXR0cignZGlzYWJsZWQnLCB0cnVlKTtcblxuXHRcdC8vIFJlcXVlc3QgZGVmYXVsdCByb29tIHNldHRpbmdzIHRvIGV4dGVuc2lvblxuXHRcdHRoaXMuc2VuZEV4dGVuc2lvblJlcXVlc3QodGhpcy5SRVFfR0VUX1JPT01fQ09ORklHKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZW1vdmUgZXhpc3Rpbmcgcm9vbS5cblx0ICovXG5cdF9vblJlbW92ZVJvb21CdENsaWNrKClcblx0e1xuXHRcdHRoaXMuc2hlbGxDdHJsLnNob3dDb25maXJtV2FybmluZygnQXJlIHlvdSBzdXJlIHlvdSB3YW50IHRvIHJlbW92ZSB0aGUgc2VsZWN0ZWQgUm9vbT8nLCAkLnByb3h5KHRoaXMuX29uUmVtb3ZlUmVtb3ZlQ29uZmlybSwgdGhpcykpO1xuXHR9XG5cblx0X29uUmVtb3ZlUmVtb3ZlQ29uZmlybSgpXG5cdHtcblx0XHRjb25zdCBzZWxlY3RlZFpvbmUgPSB0aGlzLl96b25lTGlzdEJveC5kYXRhSXRlbSh0aGlzLl96b25lTGlzdEJveC5zZWxlY3QoKSk7XG5cdFx0bGV0IHNlbGVjdGVkUm9vbSA9IHRoaXMuX3Jvb21MaXN0Qm94LmRhdGFJdGVtKHRoaXMuX3Jvb21MaXN0Qm94LnNlbGVjdCgpKTtcblxuXHRcdGlmIChzZWxlY3RlZFJvb20pXG5cdFx0e1xuXHRcdFx0Ly8gU2VuZCByZXF1ZXN0IHRvIHNlcnZlclxuXHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblx0XHRcdHBhcmFtcy5wdXRVdGZTdHJpbmcoJ3pvbmUnLCBzZWxlY3RlZFpvbmUubmFtZSk7XG5cdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCdyb29tJywgc2VsZWN0ZWRSb29tLm5hbWUpO1xuXG5cdFx0XHR0aGlzLnNlbmRFeHRlbnNpb25SZXF1ZXN0KHRoaXMuUkVRX1JFTU9WRV9ST09NLCBwYXJhbXMpO1xuXG5cdFx0XHQvLyBSZXF1ZXN0IGRhdGEgdG8gc2VydmVyIHRvIHVwZGF0ZSB0aGUgcm9vbXMgbGlzdFxuXHRcdFx0dGhpcy5fcmVxdWVzdERhdGEodHJ1ZSk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFJlbW92ZSBjb250ZW50IG9mIHJvb20gY3JlYXRpb24gcGFuZWwuXG5cdCAqL1xuXHRfb25DcmVhdGVSb29tTW9kYWxIaWRkZW4oZSlcblx0e1xuXHRcdC8vIElmIGEgbmVzdGVkIG1vZGFsIGlzIG9wZW5lZCwgaXRzIGNsb3NpbmcgY2F1c2VzIHRoZSBwYXJlbnQgbW9kYWwgdG8gYmUgY2xvc2VkIHRvbyAoQm9vdHN0cmFwIGRvZXNuJ3Qgc3VwcG9ydCBuZXN0ZWQgbW9kYWxzKVxuXHRcdC8vIEFzIGEgd29ya2Fyb3VuZCwgaGVyZSB3ZSByZXNldCB0aGUgY3NzIGNsYXNzICdtb2RhbC1vcGVuJyB3aGVuIHRoZSBuZXN0ZWQgbW9kYWwgaXMgY2xvc2VkIGFuZCBza2lwIGV2ZXJ5dGhpbmcgZWxzZVxuXHRcdC8vIEluIGFkZGl0aW9uIHdlIGhhZCB0byB1c2UgYSBjdXN0b20gbGlzdGVuZXIgb24gdGhlIGNsb3NlL2NhbmNlbCBidXR0b25zIG9mIHRoZSBuZXN0ZWQgbW9kYWwgKHNlZSBjb25maWctZ3JpZC5qcyBmb3IgZXhhbXBsZSlcblx0XHRpZiAoZS50YXJnZXQgIT09IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd6bm0tY3JlYXRlUm9vbU1vZGFsJykpXG5cdFx0e1xuXHRcdFx0JCgnYm9keScpLmFkZENsYXNzKCdtb2RhbC1vcGVuJylcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBEZXN0cm95IHNjcm9sbGluZyB0YWJzIGluIHJvb20gY3JlYXRpb24gcGFuZWxcblx0XHQkKCcjem5tLXJvb21DcmVhdG9yVGFiTmF2ICN0YWJzJykuc2Nyb2xsaW5nVGFicygnZGVzdHJveScpO1xuXG5cdFx0Ly8gUmVtb3ZlIGFsbCB0YWIgbmF2aWdhdG9yIGNvbnRlbnRcblx0XHR0aGlzLl9yb29tQ3JlYXRpb25JQnVpbGRlci5kZXN0cm95SW50ZXJmYWNlKCk7XG5cblx0XHQvLyBSZW1vdmUgbGlzdGVuZXIgZm9yIGN1c3RvbSBhY3Rpb25zIHRyaWdnZXJlZCBieSBjb25maWd1cmF0aW9uIGludGVyZmFjZVxuXHRcdCQoJyN6bm0tcm9vbUNyZWF0b3JUYWJOYXYnKS5vZmYoJ3ZhbHVlLXNldCcpO1xuXG5cdFx0Ly8gUmVzZXQgYW5kIGhpZGUgZXJyb3IgbWVzc2FnZVxuXHRcdHRoaXMuX3Jlc2V0Um9vbUNyZWF0aW9uRXJyb3IoKTtcblx0fVxuXG5cdF9vbkNvbmZpZ1ZhbHVlU2V0KGUpIC8vIFNBTUUgTUVUSE9EIERVUExJQ0FURUQgSU4gem9uZS1jb25maWd1cmF0b3IuanNcblx0e1xuXHRcdGNvbnN0IGNvbmZpZ1BhcmFtID0gZS50YXJnZXQuZGF0YTtcblxuXHRcdC8vIEhhbmRsZSBleHRlbnNpb24gbmFtZS90eXBlIGRyb3Bkb3ducyB1cGRhdGUgYW5kIHVwZGF0ZSB0aGUgbWFpbiBjbGFzcyBkcm9wZG93biBkYXRhc291cmNlIGFjY29yZGluZ2x5XG5cdFx0aWYgKGNvbmZpZ1BhcmFtLm5hbWUgPT0gJ2V4dGVuc2lvbi5uYW1lJyB8fCBjb25maWdQYXJhbS5uYW1lID09ICdleHRlbnNpb24udHlwZScgfHwgY29uZmlnUGFyYW0ubmFtZSA9PSAnZXh0ZW5zaW9uLmZpbHRlckNsYXNzJylcblx0XHR7XG5cdFx0XHQvLyBBbGwgaW52b2x2ZWQgQ29uZmlnRm9ybUl0ZW1zIG11c3QgYmUgYXZhaWxhYmxlIGFuZCBpbml0aWFsaXplZCB0byBwcm9jZWVkXG5cdFx0XHRjb25zdCBuYW1lRm9ybUl0ZW0gPSB0aGlzLl9yb29tQ3JlYXRpb25JQnVpbGRlci5nZXRDb25maWdGb3JtSXRlbSgnZXh0ZW5zaW9uLm5hbWUnKTtcblx0XHRcdGNvbnN0IHR5cGVGb3JtSXRlbSA9IHRoaXMuX3Jvb21DcmVhdGlvbklCdWlsZGVyLmdldENvbmZpZ0Zvcm1JdGVtKCdleHRlbnNpb24udHlwZScpO1xuXHRcdFx0Y29uc3QgY2xhc3NGb3JtSXRlbSA9IHRoaXMuX3Jvb21DcmVhdGlvbklCdWlsZGVyLmdldENvbmZpZ0Zvcm1JdGVtKCdleHRlbnNpb24uZmlsZScpO1xuXHRcdFx0Y29uc3QgZmlsdGVyRm9ybUl0ZW0gPSB0aGlzLl9yb29tQ3JlYXRpb25JQnVpbGRlci5nZXRDb25maWdGb3JtSXRlbSgnZXh0ZW5zaW9uLmZpbHRlckNsYXNzJyk7XG5cblx0XHRcdGlmIChuYW1lRm9ybUl0ZW0gIT0gbnVsbCAmJiB0eXBlRm9ybUl0ZW0gIT0gbnVsbCAmJiBjbGFzc0Zvcm1JdGVtICE9IG51bGwgJiYgZmlsdGVyRm9ybUl0ZW0gIT0gbnVsbClcblx0XHRcdHtcblx0XHRcdFx0Y29uc3Qgc291cmNlID0gbmFtZUZvcm1JdGVtLmRhdGE7XG5cdFx0XHRcdGxldCBjbGFzc2VzTGlzdCA9IFtdO1xuXG5cdFx0XHRcdGxldCBkYXRhID0gc291cmNlLnRyaWdnZXJEYXRhO1xuXHRcdFx0XHRmb3IgKGxldCBpID0gMDsgaSA8IGRhdGEuc2l6ZSgpOyBpKyspXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsZXQgZXh0ID0gZGF0YS5nZXRTRlNPYmplY3QoaSk7XG5cblx0XHRcdFx0XHRpZiAoZXh0LmdldFV0ZlN0cmluZygnbmFtZScpID09IG5hbWVGb3JtSXRlbS5kYXRhLnZhbHVlICYmIGV4dC5nZXRVdGZTdHJpbmcoJ3R5cGUnKSA9PSB0eXBlRm9ybUl0ZW0uZGF0YS52YWx1ZSlcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRsZXQgY2xhc3NlcyA9IGV4dC5nZXQoJ2NsYXNzZXNTdHJpbmcnKS5zcGxpdCgnLCcpOyAvLyBXZSBkb24ndCB1c2UgXCJnZXRVVGZTdHJpbmdcIiBiZWNhdXNlIHRoZSB0eXBlIGlzIFRleHQgaW4gY2FzZSBhIHZlcnkgbGFyZ2UgbGlzdCBvZiBjbGFzc2VzIGlzIHJldHVybmVkXG5cblx0XHRcdFx0XHRcdGlmIChmaWx0ZXJGb3JtSXRlbS5kYXRhLnZhbHVlID09IHRydWUpXG5cdFx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRcdGxldCBmaWx0ZXJlZENsYXNzZXMgPSBjbGFzc2VzLmZpbHRlcihmaWx0ZXJDbGFzc05hbWUpO1xuXHRcdFx0XHRcdFx0XHRjbGFzc2VzID0gZmlsdGVyZWRDbGFzc2VzO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRjbGFzc2VzTGlzdCA9IGNsYXNzZXNMaXN0LmNvbmNhdChjbGFzc2VzKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRsZXQgY3VycmVudENsYXNzID0gY2xhc3NGb3JtSXRlbS5kYXRhLnZhbHVlO1xuXG5cdFx0XHRcdC8vIElmIHRoZSBjbGFzc2VzIGxpc3QgZG9lc24ndCBjb250YWluIHRoZSBjdXJyZW50IHZhbHVlLCBjcmVhdGUgYW4gZW1wdHkgZW50cnkgYW5kIHJlc2V0IHRoZSB2YWx1ZVxuXHRcdFx0XHRpZiAoY2xhc3Nlc0xpc3QuaW5kZXhPZihjdXJyZW50Q2xhc3MpIDwgMClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGlmIChjbGFzc2VzTGlzdC5sZW5ndGggPT0gMClcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRjbGFzc2VzTGlzdC5wdXNoKCcnKTtcblx0XHRcdFx0XHRcdGN1cnJlbnRDbGFzcyA9ICcnO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0XHRjdXJyZW50Q2xhc3MgPSBjbGFzc2VzTGlzdFswXTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGxldCBtYWluQ2xhc3NEcm9wRG93biA9IGNsYXNzRm9ybUl0ZW0uX2lubmVyV2lkZ2V0O1xuXHRcdFx0XHRtYWluQ2xhc3NEcm9wRG93bi5zZXREYXRhU291cmNlKGNsYXNzZXNMaXN0KTtcblxuXHRcdFx0XHRjbGFzc0Zvcm1JdGVtLmRhdGEudmFsdWUgPSBjdXJyZW50Q2xhc3M7XG5cdFx0XHRcdGNsYXNzRm9ybUl0ZW0uX3NldFdpZGdldFZhbHVlKCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0X29uUm9vbUNyZWF0b3JDcmVhdGVCdENsaWNrKClcblx0e1xuXHRcdC8vIFJlc2V0IGFuZCBoaWRlIGVycm9yIG1lc3NhZ2Vcblx0XHR0aGlzLl9yZXNldFJvb21DcmVhdGlvbkVycm9yKCk7XG5cblx0XHQvLyBDaGVjayB2YWxpZGl0eVxuXHRcdGlmICh0aGlzLl9yb29tQ3JlYXRpb25JQnVpbGRlci5jaGVja0lzVmFsaWQoKSlcblx0XHR7XG5cdFx0XHRsZXQgY2hhbmdlcyA9IHRoaXMuX3Jvb21DcmVhdGlvbklCdWlsZGVyLmdldENoYW5nZWREYXRhKCk7XG5cblx0XHRcdGlmIChjaGFuZ2VzLnNpemUoKSA+IDApXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENoZWNrIHRoZSByb29tIG5hbWUgYWdhaW5zdCB0aGUgcm9vbXMgbGlzdCAoZHVwbGljYXRlIG5hbWVzIG5vdCBhbGxvd2VkISlcblx0XHRcdFx0aWYgKHRydWUpLy90aGlzLl92YWxpZGF0ZU5ld1Jvb21OYW1lKGNoYW5nZXMpKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0Ly8gRGlzYWJsZSByb29tIGNyZWF0aW9uIHBhbmVsXG5cdFx0XHRcdFx0dGhpcy5fZW5hYmxlQ3JlYXRlUm9vbVBhbmVsKGZhbHNlKTtcblxuXHRcdFx0XHRcdC8vIFNlbmQgc2V0dGluZ3MgdG8gc2VydmVyIGluc3RhbmNlXG5cdFx0XHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblx0XHRcdFx0XHRwYXJhbXMucHV0U0ZTQXJyYXkoJ3NldHRpbmdzJywgY2hhbmdlcyk7XG5cdFx0XHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnek5hbWUnLCB0aGlzLl96b25lTGlzdEJveC5kYXRhSXRlbSh0aGlzLl96b25lTGlzdEJveC5zZWxlY3QoKSkubmFtZSk7XG5cdFx0XHRcdFx0cGFyYW1zLnB1dEJvb2woJ25vdGlmeScsICQoJyN6bm0tbm90aWZ5Q2xpZW50c0NCJykucHJvcCgnY2hlY2tlZCcpKTtcblxuXHRcdFx0XHRcdC8vIFNlbmQgc2V0dGluZ3MgdG8gZXh0ZW5zaW9uXG5cdFx0XHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9DUkVBVEVfUk9PTSwgcGFyYW1zKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlXG5cdFx0XHRcdHtcblx0XHRcdFx0XHQvLyBTaG93IGFsZXJ0XG5cdFx0XHRcdFx0dGhpcy5zaGVsbEN0cmwuc2hvd1NpbXBsZUFsZXJ0KCdVbmFibGUgdG8gc3VibWl0IGNvbmZpZ3VyYXRpb24gYmVjYXVzZSB0aGUgUm9vbSBuYW1lIGFscmVhZHkgZXhpc3RzOyBkdXBsaWNhdGUgbmFtZXMgYXJlIG5vdCBhbGxvd2VkLicsIHRydWUpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHQvLyBTaG93IGFsZXJ0XG5cdFx0XHR0aGlzLnNoZWxsQ3RybC5zaG93U2ltcGxlQWxlcnQoJ1VuYWJsZSB0byBzdWJtaXQgUm9vbSBjb25maWd1cmF0aW9uIGR1ZSB0byBhbiBpbnZhbGlkIHZhbHVlOyBwbGVhc2UgdmVyaWZ5IHRoZSBoaWdobGlnaHRlZCBmb3JtIGZpZWxkcyBpbiBhbGwgdGFicy4nLCB0cnVlKTtcblx0XHR9XG5cdH1cblxuXHRfb25TaG93Um9vbUZpbHRlckJ0Q2xpY2soKVxuXHR7XG5cdFx0dGhpcy5fcm9vbUZpbHRlci5zaG93KCk7XG5cdH1cblxuXHRfb25TaG93VXNlckZpbHRlckJ0Q2xpY2soKVxuXHR7XG5cdFx0dGhpcy5fdXNlckZpbHRlci5zaG93KCk7XG5cdH1cblxuXHRfb25BcHBseUJ0Q2hhbmdlKClcblx0e1xuXHRcdC8vIFJlcXVlc3QgZGF0YSB0byBzZXJ2ZXJcblx0XHR0aGlzLl9yZXF1ZXN0RGF0YSh0cnVlKTtcblx0fVxuXG5cdF9vblJvb21GaWx0ZXJVcGRhdGVkKClcblx0e1xuXHRcdC8vIEVuYWJsZS9kaXNhYmxlIFwiQXBwbHlcIiBjaGVja2JveFxuXHRcdCQoJyN6bm0tYXBwbHlSb29tRmlsdGVyQ0InKS5hdHRyKCdkaXNhYmxlZCcsIHRoaXMuX3Jvb21GaWx0ZXIuZmlsdGVyRXhwcmVzc2lvbiA9PSBudWxsKTtcblxuXHRcdC8vIFJlcXVlc3QgZGF0YSB0byBzZXJ2ZXJcblx0XHR0aGlzLl9yZXF1ZXN0RGF0YSh0cnVlKTtcblx0fVxuXG5cdF9vblVzZXJGaWx0ZXJVcGRhdGVkKClcblx0e1xuXHRcdC8vIEVuYWJsZS9kaXNhYmxlIFwiQXBwbHlcIiBjaGVja2JveFxuXHRcdCQoJyN6bm0tYXBwbHlVc2VyRmlsdGVyQ0InKS5hdHRyKCdkaXNhYmxlZCcsIHRoaXMuX3VzZXJGaWx0ZXIuZmlsdGVyRXhwcmVzc2lvbiA9PSBudWxsKTtcblxuXHRcdC8vIFJlcXVlc3QgZGF0YSB0byBzZXJ2ZXJcblx0XHR0aGlzLl9yZXF1ZXN0RGF0YSh0cnVlKTtcblx0fVxuXG5cdF9vbk1vbml0b3JTZWxlY3Rpb25CdENsaWNrKClcblx0e1xuXHRcdGlmICh0aGlzLl9zZWxlY3RlZFpvbmUpXG5cdFx0e1xuXHRcdFx0Ly8gQ2FuY2VsIHByZXZpb3VzIG1vbml0b3Jpbmdcblx0XHRcdHRoaXMuX29uQ2xvc2VNb25pdG9yQnRDbGljaygpO1xuXG5cdFx0XHRsZXQgZ2V0Wm9uZVVzZXJDb3VudEhpc3RvcnkgPSBmYWxzZTtcblxuXHRcdFx0dGhpcy5fbW9uaXRvcmVkWm9uZSA9IHRoaXMuX3NlbGVjdGVkWm9uZS5uYW1lO1xuXG5cdFx0XHQvLyBab25lIG11c3QgYmUgbW9uaXRvcmVkXG5cdFx0XHRpZiAodGhpcy5fYWN0aXZlUGFuZWxUeXBlID09ICd6b25lJylcblx0XHRcdHtcblx0XHRcdFx0dGhpcy5fbW9uaXRvcmVkVHlwZSA9IHRoaXMuTU9OSVRPUkVEX1RZUEVfWk9ORTtcblx0XHRcdFx0dGhpcy5fbW9uaXRvcmVkTmFtZSA9IHRoaXMuX21vbml0b3JlZFpvbmU7XG5cblx0XHRcdFx0Z2V0Wm9uZVVzZXJDb3VudEhpc3RvcnkgPSB0cnVlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBSb29tIG11c3QgYmUgbW9uaXRvcmVkXG5cdFx0XHRpZiAodGhpcy5fYWN0aXZlUGFuZWxUeXBlID09ICdyb29tJyAmJiB0aGlzLl9zZWxlY3RlZFJvb20gIT0gdW5kZWZpbmVkKVxuXHRcdFx0e1xuXHRcdFx0XHR0aGlzLl9tb25pdG9yZWRUeXBlID0gdGhpcy5NT05JVE9SRURfVFlQRV9ST09NO1xuXHRcdFx0XHR0aGlzLl9tb25pdG9yZWROYW1lID0gdGhpcy5fc2VsZWN0ZWRSb29tLm5hbWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFVzZXIgbXVzdCBiZSBtb25pdG9yZWRcblx0XHRcdGlmICh0aGlzLl9hY3RpdmVQYW5lbFR5cGUgPT0gJ3VzZXInICYmIHRoaXMuX3NlbGVjdGVkVXNlciAhPSB1bmRlZmluZWQpXG5cdFx0XHR7XG5cdFx0XHRcdHRoaXMuX21vbml0b3JlZFR5cGUgPSB0aGlzLk1PTklUT1JFRF9UWVBFX1VTRVI7XG5cdFx0XHRcdHRoaXMuX21vbml0b3JlZE5hbWUgPSB0aGlzLl9zZWxlY3RlZFVzZXIubmFtZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU2hvdyBsb2FkaW5nIGJhclxuXHRcdFx0dGhpcy5fc3dpdGNoVmlldygnem5tLWxvYWRpbmcnKTtcblxuXHRcdFx0Ly8gUmVxdWVzdCBkYXRhIHRvIHNlcnZlclxuXHRcdFx0dGhpcy5fcmVxdWVzdERhdGEodHJ1ZSwgZ2V0Wm9uZVVzZXJDb3VudEhpc3RvcnkpO1xuXHRcdH1cblx0fVxuXG5cdF9vblNlbmRBZG1pbk1zZ0luS2V5VXAoZXZlbnQpXG5cdHtcblx0XHRpZiAoZXZlbnQua2V5ICE9PSAnRW50ZXInKVxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHR0aGlzLl9vblNlbmRBZG1pbk1zZ0J0Q2xpY2soKTtcblx0fVxuXG5cdF9vblNlbmRBZG1pbk1zZ0J0Q2xpY2soKVxuXHR7XG5cdFx0aWYgKHRoaXMuX3NlbGVjdGVkWm9uZSAmJiAkKCcjem5tLW1lc3NhZ2VJbicpLnZhbCgpICE9ICcnKVxuXHRcdHtcblx0XHRcdC8vIEJ1aWxkIHJlcXVlc3QgcGFyYW1ldGVyc1xuXHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblxuXHRcdFx0Ly8gQWx3YXlzIGluY2x1ZGUgem9uZVxuXHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnem9uZScsIHRoaXMuX3NlbGVjdGVkWm9uZS5uYW1lKTtcblxuXHRcdFx0Ly8gU2VuZCBtZXNzYWdlIHRvIHJvb20/XG5cdFx0XHRpZiAodGhpcy5fYWN0aXZlUGFuZWxUeXBlID09ICdyb29tJyAmJiB0aGlzLl9zZWxlY3RlZFJvb20gIT0gdW5kZWZpbmVkKVxuXHRcdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCdyb29tJywgdGhpcy5fc2VsZWN0ZWRSb29tLm5hbWUpO1xuXG5cdFx0XHQvLyBTZW5kIG1lc3NhZ2UgdG8gdXNlcj9cblx0XHRcdGlmICh0aGlzLl9hY3RpdmVQYW5lbFR5cGUgPT0gJ3VzZXInICYmIHRoaXMuX3NlbGVjdGVkVXNlciAhPSB1bmRlZmluZWQpXG5cdFx0XHRcdHBhcmFtcy5wdXRVdGZTdHJpbmcoJ3VzZXInLCB0aGlzLl9zZWxlY3RlZFVzZXIubmFtZSk7XG5cblx0XHRcdC8vIEFkZCBtZXNzYWdlXG5cdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCdtc2cnLCAkKCcjem5tLW1lc3NhZ2VJbicpLnZhbCgpKTtcblxuXHRcdFx0Ly8gU2VuZCByZXF1ZXN0IHRvIGV4dGVuc2lvblxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9BRE1JTl9NU0csIHBhcmFtcyk7XG5cblx0XHRcdC8vIENsZWFyIHRleHQgaW5wdXRcblx0XHRcdCQoJyN6bm0tbWVzc2FnZUluJykudmFsKCcnKTtcblx0XHR9XG5cdH1cblxuXHRfb25DbG9zZU1vbml0b3JCdENsaWNrKClcblx0e1xuXHRcdC8vIFNhdmUgcmVmLiBmb3IgbGF0ZXIgdXNhZ2Vcblx0XHRjb25zdCBtb25pdG9yZWRUeXBlID0gdGhpcy5fbW9uaXRvcmVkVHlwZTtcblxuXHRcdHRoaXMuX21vbml0b3JlZFpvbmUgPSBudWxsO1xuXHRcdHRoaXMuX21vbml0b3JlZFR5cGUgPSBudWxsO1xuXHRcdHRoaXMuX21vbml0b3JlZE5hbWUgPSBudWxsO1xuXG5cdFx0Ly8gQ2xlYXIgZ2VvbG9jYXRpb24gVUlcblx0XHR0aGlzLl9jbGVhckdlb0xvY2F0aW9uVUkoKTtcblxuXHRcdC8vIENsZWFyIGxvZyBkYXRhZ3JpZHMgZGF0YXByb3ZpZGVyc1xuXHRcdC8vIE5PVEU6IGEgdHJ5LWNhdGNoIGlzIHVzZWQgaGVyZSBiZWNhdXNlLCBmb3IgYW4gdW5rbm93biByZWFzb24sIEtlbmRvIGlzIHRocm93aW5nIGFuIGVycm9yIHdoZW4gcmVzZXR0aW5nIHRoZSBkYXRhIHNvdXJjZXMgd2hlbiB0aGUgbW9kdWxlIGlzIGRlc3Ryb3llZFxuXHRcdHRyeVxuXHRcdHtcblx0XHRcdHRoaXMuX3pvbmVFeHRMb2dHcmlkLnNldERhdGFTb3VyY2UoW10pO1xuXHRcdFx0dGhpcy5fcm9vbUV4dExvZ0dyaWQuc2V0RGF0YVNvdXJjZShbXSk7XG5cdFx0fVxuXHRcdGNhdGNoIChlKSB7IC8qIElnbm9yZSAqLyB9XG5cblx0XHQvLyBMZWF2ZSBlZGl0IG1vZGVcblx0XHR0aGlzLl9vbkNhbmNlbEJ0Q2xpY2soKTtcblxuXHRcdC8vIFJlYXJyYW5nZSBtb25pdG9yaW5nIGludGVyZmFjZVxuXHRcdHRoaXMuX3NldE1vbml0b3JpbmdJbnRlcmZhY2UoKTtcblxuXHRcdC8vIENsZWFyIHRhYiBuYXZpZ2F0b3Jcblx0XHR0aGlzLl9jbGVhclRhYnMobW9uaXRvcmVkVHlwZSk7XG5cdH1cblxuXHRfb25FZGl0QnRDbGljaygpXG5cdHtcblx0XHRpZiAoIXRoaXMuX2lzRWRpdGluZylcblx0XHR7XG5cdFx0XHQvLyBTaG93IGVkaXQgY29udHJvbHNcblx0XHRcdCQoJyN6bm0tZWRpdENvbnRyb2xzJykuc2hvdygpO1xuXG5cdFx0XHQvLyBIaWRlIGVkaXQgYnV0dG9uXG5cdFx0XHQkKCcjem5tLWVkaXRCdCcpLmhpZGUoKTtcblxuXHRcdFx0Ly8gRW5hYmxlIGVkaXRhYmxlIGZpZWxkc1xuXHRcdFx0dGhpcy5faW50ZXJmYWNlQnVpbGRlci5kaXNhYmxlSW50ZXJmYWNlKGZhbHNlKTtcblxuXHRcdFx0dGhpcy5faXNFZGl0TW9kZSA9IHRydWU7XG5cdFx0fVxuXHR9XG5cblx0X29uQ2FuY2VsQnRDbGljaygpXG5cdHtcblx0XHRpZiAodGhpcy5faXNFZGl0aW5nKVxuXHRcdHtcblx0XHRcdC8vIEhpZGUgZWRpdCBjb250cm9sc1xuXHRcdFx0JCgnI3pubS1lZGl0Q29udHJvbHMnKS5oaWRlKCk7XG5cblx0XHRcdC8vIFNob3cgZWRpdCBidXR0b25cblx0XHRcdCQoJyN6bm0tZWRpdEJ0Jykuc2hvdygpO1xuXG5cdFx0XHQvLyBEaXNhYmxlIGVkaXRhYmxlIGZpZWxkc1xuXHRcdFx0dGhpcy5faW50ZXJmYWNlQnVpbGRlci5kaXNhYmxlSW50ZXJmYWNlKHRydWUpO1xuXG5cdFx0XHR0aGlzLl9pc0VkaXRNb2RlID0gZmFsc2U7XG5cblx0XHRcdC8vIEhpZGUgdmFsaWRhdGlvbiBtZXNzYWdlc1xuXHRcdFx0dGhpcy5faW50ZXJmYWNlQnVpbGRlci5yZXNldFZhbGlkYXRpb24oKTtcblxuXHRcdFx0Ly8gUmVxdWVzdCBkYXRhIHRvIHVwZGF0ZSBpbnRlcmZhY2UgKHVwZGF0aW5nIHN1c3BlbmRlZCBpbiBlZGl0IG1vZGUpXG5cdFx0XHR0aGlzLl9yZXF1ZXN0RGF0YSh0cnVlKTtcblx0XHR9XG5cdH1cblxuXHRfb25TdWJtaXRCdENsaWNrKClcblx0e1xuXHRcdGlmICh0aGlzLl9pc0VkaXRpbmcpXG5cdFx0e1xuXHRcdFx0Ly8gQ2hlY2sgdmFsaWRpdHlcblx0XHRcdGlmICh0aGlzLl9pbnRlcmZhY2VCdWlsZGVyLmNoZWNrSXNWYWxpZCgpKVxuXHRcdFx0e1xuXHRcdFx0XHRsZXQgY2hhbmdlcyA9IHRoaXMuX2ludGVyZmFjZUJ1aWxkZXIuZ2V0Q2hhbmdlZERhdGEoKTtcblxuXHRcdFx0XHRpZiAoY2hhbmdlcy5zaXplKCkgPiAwKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0Ly9jb25zb2xlLmxvZyhjaGFuZ2VzLmdldER1bXAoKSlcblxuXHRcdFx0XHRcdC8vIFNlbmQgc2V0dGluZ3MgdG8gc2VydmVyIGluc3RhbmNlXG5cdFx0XHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblx0XHRcdFx0XHRwYXJhbXMucHV0U0ZTQXJyYXkoJ3NldHRpbmdzJywgY2hhbmdlcyk7XG5cdFx0XHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnem9uZScsIHRoaXMuX21vbml0b3JlZFpvbmUpO1xuXG5cdFx0XHRcdFx0aWYgKHRoaXMuX21vbml0b3JlZFR5cGUgPT0gdGhpcy5NT05JVE9SRURfVFlQRV9ST09NKVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdC8vIFN1Ym1pdCByb29tIHNldHRpbmdzXG5cdFx0XHRcdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCdyb29tJywgdGhpcy5fbW9uaXRvcmVkTmFtZSk7XG5cdFx0XHRcdFx0XHR0aGlzLnNlbmRFeHRlbnNpb25SZXF1ZXN0KHRoaXMuUkVRX1NFVF9ST09NX1NFVFRJTkdTLCBwYXJhbXMpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIGlmICh0aGlzLl9tb25pdG9yZWRUeXBlID09IHRoaXMuTU9OSVRPUkVEX1RZUEVfVVNFUilcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHQvLyBTdWJtaXQgdXNlciBzZXR0aW5nc1xuXHRcdFx0XHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygndXNlcicsIHRoaXMuX21vbml0b3JlZE5hbWUpO1xuXHRcdFx0XHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9TRVRfVVNFUl9TRVRUSU5HUywgcGFyYW1zKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdC8vIFN1Ym1pdCB6b25lIHNldHRpbmdzXG5cdFx0XHRcdFx0XHR0aGlzLnNlbmRFeHRlbnNpb25SZXF1ZXN0KHRoaXMuUkVRX1NFVF9aT05FX1NFVFRJTkdTLCBwYXJhbXMpO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIExlYXZlIGVkaXQgbW9kZVxuXHRcdFx0XHRcdHRoaXMuX29uQ2FuY2VsQnRDbGljaygpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRlbHNlXG5cdFx0XHR7XG5cdFx0XHRcdC8vIFNob3cgYWxlcnRcblx0XHRcdFx0dGhpcy5zaGVsbEN0cmwuc2hvd1NpbXBsZUFsZXJ0KCdVbmFibGUgdG8gc3VibWl0IGNoYW5nZXMgZHVlIHRvIGFuIGludmFsaWQgdmFsdWU7IHBsZWFzZSB2ZXJpZnkgdGhlIGhpZ2hsaWdodGVkIGZvcm0gZmllbGRzIGluIGFsbCB0YWJzLicsIHRydWUpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdF9vblRpbWVSYW5nZUNoYW5nZSgpXG5cdHtcblx0XHRsZXQgdmFsdWVzID0gdGhpcy5fdGltZVNsaWRlci52YWx1ZSgpO1xuXG5cdFx0aWYgKHZhbHVlc1swXSA9PSB2YWx1ZXNbMV0pXG5cdFx0e1xuXHRcdFx0aWYgKHZhbHVlc1sxXSA9PSAtMjQpXG5cdFx0XHRcdHZhbHVlc1sxXSA9IC0yMztcblxuXHRcdFx0dmFsdWVzWzBdID0gdmFsdWVzWzFdIC0gMTtcblxuXHRcdFx0Ly8gUmVzZXQgdGhlIHRpbWUgcmFuZ2Ugc2xpZGVyIHZhbHVlICh3ZSBuZWVkIHRvIHVzZSBzZXRUaW1lb3V0XG5cdFx0XHQvLyBiYWNhdXNlIGRvaW5nIGl0IGluIHRoZSBjaGFuZ2UgZXZlbnQgbGlzdGVuZXIgZG9lc24ndCByZWRyYXcgdGhlIHNsaWRlcilcblx0XHRcdHNldFRpbWVvdXQoJC5wcm94eSggZnVuY3Rpb24odmFsdWVzKSB7IHRoaXMuX3RpbWVTbGlkZXIudmFsdWUodmFsdWVzKTsgfSwgdGhpcyksIDEwLCB2YWx1ZXMpO1xuXHRcdH1cblxuXHRcdHRoaXMuX3VzZXJDb3VudENoYXJ0LnJhbmdlID0gdmFsdWVzO1xuXHR9XG5cblx0X29uV2luZG93UmVzaXplKClcblx0e1xuXHRcdC8vIFJlZHJhdyBjaGFydHNcblx0XHR0aGlzLl91c2VyQ291bnRDaGFydC5yZWRyYXcoKTtcblx0XHR0aGlzLl9wYWNrZXRRdWV1ZUNoYXJ0LnJlZHJhdygpO1xuXHRcdHRoaXMuX2Ryb3BwZWRNc2dDaGFydC5yZWRyYXcoKTtcblx0XHR0aGlzLl93cml0dGVuRGF0YUNoYXJ0LnJlZHJhdygpO1xuXHRcdHRoaXMuX3JlYWREYXRhQ2hhcnQucmVkcmF3KCk7XG5cblx0XHQvLyBSZWRyYXcgdGltZSByYW5nZSBzbGlkZXJcblx0XHR0aGlzLl90aW1lU2xpZGVyLnJlc2l6ZSgpO1xuXHR9XG5cblx0X29uV29yZHNSZWxvYWRCdENsaWNrKClcblx0e1xuXHRcdGlmICh0aGlzLl9tb25pdG9yZWRUeXBlID09IHRoaXMuTU9OSVRPUkVEX1RZUEVfWk9ORSlcblx0XHR7XG5cdFx0XHQvLyBTZW5kIHJlcXVlc3QgdG8gZXh0ZW5zaW9uXG5cdFx0XHRsZXQgcGFyYW1zID0gbmV3IFNGUzJYLlNGU09iamVjdCgpO1xuXHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnem9uZScsIHRoaXMuX21vbml0b3JlZE5hbWUpO1xuXG5cdFx0XHR0aGlzLnNlbmRFeHRlbnNpb25SZXF1ZXN0KHRoaXMuUkVRX1JFTE9BRF9XT1JEUywgcGFyYW1zKTtcblx0XHR9XG5cdH1cblxuXHRfb25ab25lRXh0UmVsb2FkQnRDbGljaygpXG5cdHtcblx0XHRpZiAodGhpcy5fbW9uaXRvcmVkVHlwZSA9PSB0aGlzLk1PTklUT1JFRF9UWVBFX1pPTkUpXG5cdFx0e1xuXHRcdFx0Ly8gU2VuZCByZXF1ZXN0IHRvIGV4dGVuc2lvblxuXHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblx0XHRcdHBhcmFtcy5wdXRVdGZTdHJpbmcoJ3pvbmUnLCB0aGlzLl9tb25pdG9yZWROYW1lKTtcblxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9SRUxPQURfWk9ORV9FWFQsIHBhcmFtcyk7XG5cdFx0fVxuXHR9XG5cblx0X29uRGlzY29ubmVjdEJ0Q2xpY2soKVxuXHR7XG5cdFx0aWYgKHRoaXMuX21vbml0b3JlZFR5cGUgPT0gdGhpcy5NT05JVE9SRURfVFlQRV9VU0VSKVxuXHRcdHtcblx0XHRcdC8vIFNlbmQgcmVxdWVzdCB0byBleHRlbnNpb25cblx0XHRcdGxldCBwYXJhbXMgPSBuZXcgU0ZTMlguU0ZTT2JqZWN0KCk7XG5cdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCd6b25lJywgdGhpcy5fbW9uaXRvcmVkWm9uZSk7XG5cdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCd1c2VyJywgdGhpcy5fbW9uaXRvcmVkTmFtZSk7XG5cblx0XHRcdHRoaXMuc2VuZEV4dGVuc2lvblJlcXVlc3QodGhpcy5SRVFfRElTQ09OTkVDVF9VU0VSLCBwYXJhbXMpO1xuXHRcdH1cblx0fVxuXG5cdF9vbktpY2tCdENsaWNrKClcblx0e1xuXHRcdGlmICh0aGlzLl9tb25pdG9yZWRUeXBlID09IHRoaXMuTU9OSVRPUkVEX1RZUEVfVVNFUilcblx0XHR7XG5cdFx0XHQvLyBTZW5kIHJlcXVlc3QgdG8gZXh0ZW5zaW9uXG5cdFx0XHRsZXQgcGFyYW1zID0gbmV3IFNGUzJYLlNGU09iamVjdCgpO1xuXHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnem9uZScsIHRoaXMuX21vbml0b3JlZFpvbmUpO1xuXHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygndXNlcicsIHRoaXMuX21vbml0b3JlZE5hbWUpO1xuXHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnbXNnJywgJCgnI3pubS1raWNrTXNnSW4nKS52YWwoKSk7XG5cdFx0XHRwYXJhbXMucHV0SW50KCdkZWxheScsICh0aGlzLl9raWNrRGVsYXlJbi52YWx1ZSgpICE9IG51bGwgPyBOdW1iZXIodGhpcy5fa2lja0RlbGF5SW4udmFsdWUoKSkgOiB0aGlzLktJQ0tfQkFOX0RFRkFVTFRfREVMQVkpKTtcblxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9LSUNLX1VTRVIsIHBhcmFtcyk7XG5cblx0XHRcdC8vIFJlc2V0IG1lc3NhZ2Vcblx0XHRcdCQoJyN6bm0ta2lja01zZ0luJykudmFsKCcnKTtcblx0XHR9XG5cdH1cblxuXHRfb25CYW5CdENsaWNrKClcblx0e1xuXHRcdGlmICh0aGlzLl9tb25pdG9yZWRUeXBlID09IHRoaXMuTU9OSVRPUkVEX1RZUEVfVVNFUilcblx0XHR7XG5cdFx0XHQvLyBTZW5kIHJlcXVlc3QgdG8gZXh0ZW5zaW9uXG5cdFx0XHRsZXQgcGFyYW1zID0gbmV3IFNGUzJYLlNGU09iamVjdCgpO1xuXHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnem9uZScsIHRoaXMuX21vbml0b3JlZFpvbmUpO1xuXHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygndXNlcicsIHRoaXMuX21vbml0b3JlZE5hbWUpO1xuXHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnbXNnJywgJCgnI3pubS1iYW5Nc2dJbicpLnZhbCgpKTtcblx0XHRcdHBhcmFtcy5wdXRVdGZTdHJpbmcoJ3JzbicsICQoJyN6bm0tYmFuUnNuSW4nKS52YWwoKSk7XG5cdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCdtb2RlJywgdGhpcy5fYmFuTW9kZURkLnNlbGVjdCgpID4gMCA/IHRoaXMuX2Jhbk1vZGVEZC52YWx1ZSgpIDogJ05BTUUnKTtcblx0XHRcdHBhcmFtcy5wdXRJbnQoJ2RlbGF5JywgKHRoaXMuX2JhbkRlbGF5SW4udmFsdWUoKSAhPSBudWxsID8gTnVtYmVyKHRoaXMuX2JhbkRlbGF5SW4udmFsdWUoKSkgOiB0aGlzLktJQ0tfQkFOX0RFRkFVTFRfREVMQVkpKTtcblxuXHRcdFx0bGV0IGR1cmF0aW9uID0gdGhpcy5fYmFuRHVyYXRpb25Jbi52YWx1ZSgpICE9IG51bGwgPyBOdW1iZXIodGhpcy5fYmFuRHVyYXRpb25Jbi52YWx1ZSgpKSA6IDE7XG5cblx0XHRcdGlmICh0aGlzLl9iYW5EdXJVbml0RGQudmFsdWUoKSA9PSAnaG91cnMnKVxuXHRcdFx0XHRkdXJhdGlvbiA9IGR1cmF0aW9uICogNjA7XG5cdFx0XHRlbHNlIGlmICh0aGlzLl9iYW5EdXJVbml0RGQudmFsdWUoKSA9PSAnZGF5cycpXG5cdFx0XHRcdGR1cmF0aW9uID0gZHVyYXRpb24gKiA2MCAqIDI0O1xuXG5cdFx0XHRwYXJhbXMucHV0SW50KCdkdXJhdGlvbicsIGR1cmF0aW9uKTtcblxuXHRcdFx0dGhpcy5zZW5kRXh0ZW5zaW9uUmVxdWVzdCh0aGlzLlJFUV9CQU5fVVNFUiwgcGFyYW1zKTtcblxuXHRcdFx0Ly8gUmVzZXQgbWVzc2FnZSBhbmQgcmVhc29uXG5cdFx0XHQkKCcjem5tLWJhbk1zZ0luJykudmFsKCcnKTtcblx0XHRcdCQoJyN6bm0tYmFuUnNuSW4nKS52YWwoJycpO1xuXHRcdH1cblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFBSSVZBVEUgTUVUSE9EU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdF9zZXRNb25pdG9yaW5nSW50ZXJmYWNlKClcblx0e1xuXHRcdGNvbnN0IGVuYWJsZWQgPSAodGhpcy5fbW9uaXRvcmVkVHlwZSAhPSBudWxsICYmIHRoaXMuX21vbml0b3JlZE5hbWUgIT0gbnVsbCk7XG5cblx0XHQvLyBTaG93L2hpZGUgaGVhZGVyIGFuZCBmb290ZXJcblx0XHRpZiAoZW5hYmxlZClcblx0XHR7XG5cdFx0XHR0aGlzLl9zd2l0Y2hWaWV3KGB6bm0tJHt0aGlzLl9tb25pdG9yZWRUeXBlfU1vbml0b3JgKTtcblxuXHRcdFx0Ly8gSGVhZGVyIHRpdGxlXG5cdFx0XHRsZXQgdGl0bGUgPSAnTm93IG1vbml0b3JpbmcgJztcblxuXHRcdFx0aWYgKHRoaXMuX21vbml0b3JlZFR5cGUgPT0gdGhpcy5NT05JVE9SRURfVFlQRV9VU0VSKVxuXHRcdFx0XHR0aXRsZSArPSBgVXNlcjogPHN0cm9uZz4ke3RoaXMuX21vbml0b3JlZE5hbWV9PC9zdHJvbmc+IChab25lOiAke3RoaXMuX21vbml0b3JlZFpvbmV9KWA7XG5cdFx0XHRlbHNlIGlmICh0aGlzLl9tb25pdG9yZWRUeXBlID09IHRoaXMuTU9OSVRPUkVEX1RZUEVfUk9PTSlcblx0XHRcdFx0dGl0bGUgKz0gYFJvb206IDxzdHJvbmc+JHt0aGlzLl9tb25pdG9yZWROYW1lfTwvc3Ryb25nPiAoWm9uZTogJHt0aGlzLl9tb25pdG9yZWRab25lfSlgO1xuXHRcdFx0ZWxzZVxuXHRcdFx0XHR0aXRsZSArPSBgWm9uZTogPHN0cm9uZz4ke3RoaXMuX21vbml0b3JlZFpvbmV9PC9zdHJvbmc+YDtcblxuXHRcdFx0JCgnI3pubS1tb25pdG9yZWRIZWFkZXInKS5odG1sKHRpdGxlKTtcblx0XHRcdCQoJyN6bm0tbW9uaXRvcmVkRm9vdGVyJykuc2hvdygpO1xuXG5cdFx0XHQvLyBTaG93IHBhbmVsXG5cdFx0XHR0aGlzLl9zd2l0Y2hQYW5lbCgnem5tLW1haW5QYW5lbCcpO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0dGhpcy5fc3dpdGNoVmlldygnem5tLXNlbGVjdCcpO1xuXG5cdFx0XHQkKCcjem5tLW1vbml0b3JlZEhlYWRlcicpLmh0bWwoJycpO1xuXHRcdFx0JCgnI3pubS1tb25pdG9yZWRGb290ZXInKS5oaWRlKCk7XG5cblx0XHRcdC8vIFNob3cgcGFuZWxcblx0XHRcdHRoaXMuX3N3aXRjaFBhbmVsKCd6bm0tc2lkZWJhclBhbmVsJyk7XG5cdFx0fVxuXHR9XG5cblx0X3N3aXRjaFZpZXcodmlld0lkKVxuXHR7XG5cdFx0ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3pubS12aWV3c3RhY2snKS5zZWxlY3RlZEVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh2aWV3SWQpO1xuXHR9XG5cblx0X3N3aXRjaFBhbmVsKHBhbmVsSWQpXG5cdHtcblx0XHRkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnem5tLXZpZXcnKS5zZWxlY3RlZFBhbmVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQocGFuZWxJZCk7XG5cdH1cblxuXHQvKipcblx0ICogQnVpbGQgdGhlIHBvbGxpbmcgcmVxdWVzdCB0byBiZSBzZW50IHRvIHRoZSBzZXJ2ZXIsIGJhc2VkIG9uIHRoZSBzZWxlY3Rpb25zIGFuZCBvdGhlciBzZXR0aW5ncyBpbiB0aGUgYWNjb3JkaW9uLlxuXHQgKi9cblx0X3JlcXVlc3REYXRhKG5ld0lkID0gZmFsc2UsIGdldFpvbmVVc2VyQ291bnRIaXN0b3J5ID0gZmFsc2UpXG5cdHtcblx0XHQvLyBDbGVhciBwcmV2aW91cyByZXF1ZXN0IHNjaGVkdWxpbmdcblx0XHRjbGVhclRpbWVvdXQodGhpcy5fcmVxdWVzdFRpbWVyKTtcblxuXHRcdC8vIENoZWNrIGlmIGNvbm5lY3Rpb24gaXMgc3RpbGwgYXZhaWxhYmxlXG5cdFx0aWYgKHRoaXMuc21hcnRGb3guaXNDb25uZWN0ZWQpXG5cdFx0e1xuXHRcdFx0aWYgKG5ld0lkKVxuXHRcdFx0XHR0aGlzLl9jdXJyZW50UmVxdWVzdElkKys7XG5cblx0XHRcdC8vIEJ1aWxkIHJlcXVlc3QgcGFyYW1ldGVyc1xuXHRcdFx0bGV0IHBhcmFtcyA9IG5ldyBTRlMyWC5TRlNPYmplY3QoKTtcblxuXHRcdFx0Ly8gVGhlIHVwZGF0ZWQgem9uZXMvcm9vbXMvdXNlcnMgbGlzdHMgYXJlIHJlcXVlc3RlZCBpZiB0aGUgY29ycmVzcG9uZGluZyBwYW5lbCBpcyBkaXNwbGF5ZWQgb25seVxuXHRcdFx0Y29uc3QgZ2V0Wm9uZXMgPSAodGhpcy5fYWN0aXZlUGFuZWxUeXBlID09ICd6b25lJyk7XG5cdFx0XHRjb25zdCBnZXRSb29tcyA9ICh0aGlzLl9hY3RpdmVQYW5lbFR5cGUgPT0gJ3Jvb20nICYmIHRoaXMuX3NlbGVjdGVkWm9uZSAhPSB1bmRlZmluZWQpO1xuXHRcdFx0Y29uc3QgZ2V0VXNlcnMgPSAodGhpcy5fYWN0aXZlUGFuZWxUeXBlID09ICd1c2VyJyAmJiB0aGlzLl9zZWxlY3RlZFpvbmUgIT0gdW5kZWZpbmVkKTtcblxuXHRcdFx0Ly8gLS0tIFpPTkVTIC0tLVxuXHRcdFx0cGFyYW1zLnB1dEJvb2woJ3pvbmVzJywgZ2V0Wm9uZXMpO1xuXG5cdFx0XHQvLyBST09NUyAmIFVTRVJTXG5cdFx0XHRpZiAoZ2V0Um9vbXMgfHwgZ2V0VXNlcnMpXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENvbW1vbiBmaWx0ZXJpbmcgcGFyYW1zOlxuXG5cdFx0XHRcdC8vIGEpIHpvbmUgbmFtZVxuXHRcdFx0XHRwYXJhbXMucHV0VXRmU3RyaW5nKCd6b25lJywgdGhpcy5fc2VsZWN0ZWRab25lLm5hbWUpO1xuXG5cdFx0XHRcdC8vIGIpIGdyb3VwIG5hbWVcblx0XHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygnZ3JvdXAnLCB0aGlzLl9zZWxlY3RlZEdyb3VwLm5hbWUpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBST09NU1xuXHRcdFx0cGFyYW1zLnB1dEJvb2woJ3Jvb21zJywgZ2V0Um9vbXMpO1xuXHRcdFx0aWYgKGdldFJvb21zKVxuXHRcdFx0e1xuXHRcdFx0XHQvLyBGaWx0ZXJpbmcgcGFyYW1zOlxuXG5cdFx0XHRcdC8vIGMpIGFkdmFuY2VkIGZpbHRlcmluZyBwYXJhbXNcblx0XHRcdFx0aWYgKCQoJyN6bm0tYXBwbHlSb29tRmlsdGVyQ0InKS5wcm9wKCdjaGVja2VkJykgJiYgdGhpcy5fcm9vbUZpbHRlci5maWx0ZXJFeHByZXNzaW9uICE9IG51bGwpXG5cdFx0XHRcdFx0cGFyYW1zLnB1dFNGU0FycmF5KCdyRmlsdGVyJywgdGhpcy5fcm9vbUZpbHRlci5maWx0ZXJFeHByZXNzaW9uLnRvU0ZTQXJyYXkoKSk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFVTRVJTXG5cdFx0XHRwYXJhbXMucHV0Qm9vbCgndXNlcnMnLCBnZXRVc2Vycyk7XG5cdFx0XHRpZiAoZ2V0VXNlcnMpXG5cdFx0XHR7XG5cdFx0XHRcdC8vIEZpbHRlcmluZyBwYXJhbXM6XG5cblx0XHRcdFx0Ly8gYykgcm9vbSBuYW1lXG5cdFx0XHRcdGlmICh0aGlzLl9zZWxlY3RlZFJvb20pXG5cdFx0XHRcdFx0cGFyYW1zLnB1dFV0ZlN0cmluZygncm9vbScsIHRoaXMuX3NlbGVjdGVkUm9vbS5uYW1lKTtcblxuXHRcdFx0XHQvLyBkKSBhZHZhbmNlZCBmaWx0ZXJpbmcgcGFyYW1zXG5cdFx0XHRcdGlmICgkKCcjem5tLWFwcGx5VXNlckZpbHRlckNCJykucHJvcCgnY2hlY2tlZCcpICYmIHRoaXMuX3VzZXJGaWx0ZXIuZmlsdGVyRXhwcmVzc2lvbiAhPSBudWxsKVxuXHRcdFx0XHRcdHBhcmFtcy5wdXRTRlNBcnJheSgndUZpbHRlcicsIHRoaXMuX3VzZXJGaWx0ZXIuZmlsdGVyRXhwcmVzc2lvbi50b1NGU0FycmF5KCkpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyAtLS0gQ1VSUkVOVExZIE1PTklUT1JFRCBEQVRBIC0tLVxuXHRcdFx0aWYgKHRoaXMuX21vbml0b3JlZFR5cGUgIT0gbnVsbCAmJiB0aGlzLl9tb25pdG9yZWROYW1lICE9IG51bGwpXG5cdFx0XHR7XG5cdFx0XHRcdGxldCBtb25pdG9yZWRPYmogPSB0aGlzLl9nZXRCYXNpY01vbml0b3JlZE9iamVjdCgpO1xuXG5cdFx0XHRcdGlmICh0aGlzLl9tb25pdG9yZWRUeXBlID09IHRoaXMuTU9OSVRPUkVEX1RZUEVfWk9ORSlcblx0XHRcdFx0XHRtb25pdG9yZWRPYmoucHV0Qm9vbCgndWMnLCBnZXRab25lVXNlckNvdW50SGlzdG9yeSk7XG5cblx0XHRcdFx0cGFyYW1zLnB1dFNGU09iamVjdCgnbW9uaXRvcmVkJywgbW9uaXRvcmVkT2JqKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU2V0IHJlcXVlc3QgaWQ7IHdoZW4gYSByZXNwb25zZSBpcyByZWNlaXZlZCwgd2UgY2hlY2sgaXRzIGlkIG1hdGNoZXMgdGhlIGN1cnJlbnQgcmVxdWVzdCBpZDogaWYgbm90LCB0aGUgcmVzcG9uc2UgaXMgZGlzY2FyZGVkXG5cdFx0XHRwYXJhbXMucHV0SW50KCdpZCcsIHRoaXMuX2N1cnJlbnRSZXF1ZXN0SWQpO1xuXG5cdFx0XHQvLyBTZW5kIHJlcXVlc3QgdG8gZXh0ZW5zaW9uXG5cdFx0XHR0aGlzLnNlbmRFeHRlbnNpb25SZXF1ZXN0KHRoaXMuUkVRX0dFVF9EQVRBLCBwYXJhbXMpO1xuXG5cdFx0XHQvLyBTY2hlZHVsZSBuZXh0IHJlcXVlc3Rcblx0XHRcdHRoaXMuX3JlcXVlc3RUaW1lciA9IHNldFRpbWVvdXQoJC5wcm94eSh0aGlzLl9yZXF1ZXN0RGF0YSwgdGhpcyksIE51bWJlcih0aGlzLl9pbnRlcnZhbERyb3BEb3duLnZhbHVlKCkpICogMTAwMCk7XG5cdFx0fVxuXHR9XG5cblx0X2dldEJhc2ljTW9uaXRvcmVkT2JqZWN0KClcblx0e1xuXHRcdGxldCBtb25pdG9yZWRPYmogPSBuZXcgU0ZTMlguU0ZTT2JqZWN0KCk7XG5cblx0XHRtb25pdG9yZWRPYmoucHV0VXRmU3RyaW5nKCd6b25lJywgdGhpcy5fbW9uaXRvcmVkWm9uZSk7XG5cdFx0bW9uaXRvcmVkT2JqLnB1dFV0ZlN0cmluZygndHlwZScsIHRoaXMuX21vbml0b3JlZFR5cGUpO1xuXHRcdG1vbml0b3JlZE9iai5wdXRVdGZTdHJpbmcoJ25hbWUnLCB0aGlzLl9tb25pdG9yZWROYW1lKTtcblxuXHRcdHJldHVybiBtb25pdG9yZWRPYmo7XG5cdH1cblxuXHRfc2V0Wm9uZXNEYXRhUHJvdmlkZXIoem9uZXNEYXRhKVxuXHR7XG5cdFx0dGhpcy5fc2V0TGlzdERhdGFQcm92aWRlcih0aGlzLl96b25lTGlzdEJveCwgem9uZXNEYXRhLCB0cnVlKTtcblx0fVxuXG5cdF9zZXRSb29tc0RhdGFQcm92aWRlcihyb29tc0RhdGEpXG5cdHtcblx0XHR0aGlzLl9zZXRMaXN0RGF0YVByb3ZpZGVyKHRoaXMuX3Jvb21MaXN0Qm94LCByb29tc0RhdGEsIHRydWUpO1xuXG5cdFx0Ly8gU2V0IFJlbW92ZSBidXR0b24gc3RhdGVcblx0XHQkKCcjem5tLXJlbW92ZVJvb21CdCcpLmF0dHIoJ2Rpc2FibGVkJywgdGhpcy5fc2VsZWN0ZWRSb29tID09IHVuZGVmaW5lZCk7XG5cdH1cblxuXHRfc2V0VXNlcnNEYXRhUHJvdmlkZXIodXNlcnNEYXRhKVxuXHR7XG5cdFx0dGhpcy5fc2V0TGlzdERhdGFQcm92aWRlcih0aGlzLl91c2VyTGlzdEJveCwgdXNlcnNEYXRhKTtcblx0fVxuXG5cdF9zZXRMaXN0RGF0YVByb3ZpZGVyKGxpc3RXaWRnZXQsIGxpc3REYXRhLCBjb3VudFVzZXJzID0gZmFsc2UpXG5cdHtcblx0XHQvLyBTYXZlIHJlZmVyZW5jZSB0byBzZWxlY3RlZCBpdGVtIG5hbWVcblx0XHQvLyBOT1RFOiBhcyB3ZSBhcmUgc3Vic3RpdHV0aW5nIHRoZSB3aG9sZSBkYXRhIHNvdXJjZSwgd2UgbmVlZCBpdCB0byByZS1zZWxlY3QgdGhlIHNhbWUgaXRlbSBhZnRlciB1cGRhdGVcblx0XHRsZXQgc2VsZWN0ZWREYXRhSXRlbSA9IGxpc3RXaWRnZXQuZGF0YUl0ZW0obGlzdFdpZGdldC5zZWxlY3QoKSk7XG5cdFx0bGV0IHNlbGVjdGVkRGF0YUl0ZW1OYW1lID0gc2VsZWN0ZWREYXRhSXRlbSA/IHNlbGVjdGVkRGF0YUl0ZW0ubmFtZSA6IG51bGw7XG5cblx0XHRsZXQgZGF0YUFycmF5ID0gW107XG5cblx0XHQvLyBDb252ZXJ0IGRhdGEgY29taW5nIGZyb20gc2VydmVyXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBsaXN0RGF0YS5zaXplKCk7IGkrKylcblx0XHR7XG5cdFx0XHRsZXQgaXRlbURhdGEgPSBsaXN0RGF0YS5nZXRTRlNPYmplY3QoaSk7XG5cblx0XHRcdGxldCBpdGVtID0ge307XG5cdFx0XHRpdGVtLm5hbWUgPSBpdGVtRGF0YS5nZXRVdGZTdHJpbmcoJ25hbWUnKTtcblxuXHRcdFx0aWYgKGNvdW50VXNlcnMpXG5cdFx0XHRcdGl0ZW0udXNlcnMgPSBpdGVtRGF0YS5nZXRJbnQoJ3VzZXJzJyk7XG5cblx0XHRcdGRhdGFBcnJheS5wdXNoKGl0ZW0pO1xuXHRcdH1cblxuXHRcdC8vIENyZWF0ZSBuZXcgZGF0YSBzb3VyY2Vcblx0XHRsZXQgbGlzdERTID0gbmV3IGtlbmRvLmRhdGEuRGF0YVNvdXJjZSh7XG5cdFx0XHRkYXRhOiBkYXRhQXJyYXksXG5cdFx0XHRzY2hlbWE6IHtcblx0XHRcdFx0bW9kZWw6IHtcblx0XHRcdFx0XHRpZDogJ25hbWUnXG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRzb3J0OiB7XG5cdFx0XHRcdGZpZWxkOiAnbmFtZScsXG5cdFx0XHRcdGRpcjogJ2FzYydcblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdC8vIEFzc2lnbiBkYXRhIHNvdXJjZSB0byBsaXN0XG5cdFx0bGlzdFdpZGdldC5zZXREYXRhU291cmNlKGxpc3REUyk7XG5cblx0XHQvLyBTZWxlY3QgYWdhaW4gcHJldmlvdXNseSBzZWxlY3RlZCBpdGVtXG5cdFx0aWYgKHNlbGVjdGVkRGF0YUl0ZW1OYW1lICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0c2VsZWN0ZWREYXRhSXRlbSA9IGxpc3REUy5nZXQoc2VsZWN0ZWREYXRhSXRlbU5hbWUpO1xuXG5cdFx0XHRpZiAoc2VsZWN0ZWREYXRhSXRlbSlcblx0XHRcdHtcblx0XHRcdFx0bGV0IHNlbGVjdGVkRWxlbWVudCA9IGxpc3RXaWRnZXQud3JhcHBlci5maW5kKCdbZGF0YS11aWQ9XCInICsgc2VsZWN0ZWREYXRhSXRlbS51aWQgKyAnXCJdJyk7XG5cdFx0XHRcdGxpc3RXaWRnZXQuc2VsZWN0KHNlbGVjdGVkRWxlbWVudCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gUmVzZXQgbWFpbiBjb250cm9sIHN0YXRlXG5cdFx0dGhpcy5fc2V0TWFpbkNvbnRyb2xzRW5hYmxlZCgpO1xuXHR9XG5cblx0X3NldEdyb3Vwc0RhdGFQcm92aWRlcihncm91cHNEYXRhKVxuXHR7XG5cdFx0Ly8gQ3JlYXRlIEdyb3VwcyBhcnJheSwgYWRkaW5nIGNvbW1vbiBlbnRyaWVzXG5cdFx0bGV0IGdyb3Vwc0FycmF5ID0gW1xuXHRcdFx0dGhpcy5fZ2V0R3JvdXBPYmooJycsIHRoaXMuQU5ZX0xBQkVMKSxcblx0XHRcdHRoaXMuX2dldEdyb3VwT2JqKHRoaXMuREVGQVVMVF9HUk9VUF9OQU1FKVxuXHRcdF07XG5cblx0XHQvLyBTYXZlIHJlZmVyZW5jZSB0byBzZWxlY3RlZCBncm91cCBuYW1lXG5cdFx0Ly8gTk9URTogYXMgd2UgYXJlIHN1YnN0aXR1dGluZyB0aGUgd2hvbGUgZGF0YSBzb3VyY2UsIHdlIG5lZWQgaXQgdG8gcmUtc2VsZWN0IHRoZSBzYW1lIGl0ZW0gYWZ0ZXIgdXBkYXRlXG5cdFx0bGV0IHNlbGVjdGVkRGF0YUl0ZW0gPSB0aGlzLl9zZWxlY3RlZEdyb3VwO1xuXHRcdGxldCBzZWxlY3RlZERhdGFJdGVtTmFtZSA9IHNlbGVjdGVkRGF0YUl0ZW0gPyBzZWxlY3RlZERhdGFJdGVtLm5hbWUgOiBudWxsO1xuXG5cdFx0aWYgKGdyb3Vwc0RhdGEgIT0gbnVsbClcblx0XHR7XG5cdFx0XHRmb3IgKGxldCBpID0gMDsgaSA8IGdyb3Vwc0RhdGEubGVuZ3RoOyBpKyspXG5cdFx0XHR7XG5cdFx0XHRcdGlmIChncm91cHNEYXRhW2ldICE9IHRoaXMuREVGQVVMVF9HUk9VUF9OQU1FKSAvLyBEZWZhdWx0IGdyb3VwIHdhcyBhZGRlZCBiZWZvcmVcblx0XHRcdFx0XHRncm91cHNBcnJheS5wdXNoKHRoaXMuX2dldEdyb3VwT2JqKGdyb3Vwc0RhdGFbaV0pKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDcmVhdGUgbmV3IGRhdGEgc291cmNlXG5cdFx0bGV0IGdyb3VwRFMgPSBuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKHtcblx0XHRcdGRhdGE6IGdyb3Vwc0FycmF5LFxuXHRcdFx0c2NoZW1hOiB7XG5cdFx0XHRcdG1vZGVsOiB7XG5cdFx0XHRcdFx0aWQ6ICduYW1lJ1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvLyBBc3NpZ24gZGF0YSBzb3VyY2UgdG8gZHJvcGRvd25cblx0XHR0aGlzLl9ncm91cHNEcm9wRG93bi5zZXREYXRhU291cmNlKGdyb3VwRFMpO1xuXG5cdFx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Ly8gU2VsZWN0IHByZXZpb3VzbHkgc2VsZWN0ZWQgaXRlbVxuXHRcdHNlbGVjdGVkRGF0YUl0ZW0gPSBncm91cERTLmdldChzZWxlY3RlZERhdGFJdGVtTmFtZSk7XG5cblx0XHQvLyBJZiBncm91cCBpcyBub3QgZm91bmQsIHNlbGVjdCB0aGUgZGVmYXVsdCBvbmVcblx0XHRpZiAoc2VsZWN0ZWREYXRhSXRlbSA9PSB1bmRlZmluZWQpXG5cdFx0XHRzZWxlY3RlZERhdGFJdGVtID0gZ3JvdXBEUy5nZXQodGhpcy5ERUZBVUxUX0dST1VQX05BTUUpO1xuXG5cdFx0dGhpcy5fZ3JvdXBzRHJvcERvd24uc2VsZWN0KGZ1bmN0aW9uKGRhdGFJdGVtKSB7XG5cdFx0XHRyZXR1cm4gZGF0YUl0ZW0ubmFtZSA9PT0gc2VsZWN0ZWREYXRhSXRlbS5uYW1lO1xuXHRcdH0pO1xuXHR9XG5cblx0X2dldEdyb3VwT2JqKG5hbWUsIGxhYmVsID0gbnVsbClcblx0e1xuXHRcdHJldHVybiB7XG5cdFx0XHRuYW1lOiBuYW1lLFxuXHRcdFx0bGFiZWw6IChsYWJlbCAhPSBudWxsID8gbGFiZWwgOiBuYW1lKVxuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgdGhlIFNjb3BlIGxhYmVsIGluIHRoZSBSb29tcyBwYW5lbCBhbmQgaW4gdGhlIFVzZXJzIHBhbmVsLlxuXHQgKi9cblx0X3NldFNjb3BlTGFiZWwoKVxuXHR7XG5cdFx0bGV0IHJvb21TY29wZSA9ICcnO1xuXHRcdGxldCB1c2VyU2NvcGUgPSAnJztcblxuXHRcdGlmICh0aGlzLl9zZWxlY3RlZFpvbmUpXG5cdFx0e1xuXHRcdFx0bGV0IHpvbmVOYW1lID0gdGhpcy5fc2VsZWN0ZWRab25lLm5hbWU7XG5cdFx0XHRyb29tU2NvcGUgPSB0aGlzLl9nZXRTY29wZUxhYmVsUGFydCgnWm9uZTonLCB6b25lTmFtZSk7XG5cblx0XHRcdGxldCBzZWxlY3RlZEdyb3VwID0gdGhpcy5fc2VsZWN0ZWRHcm91cDtcblx0XHRcdGxldCBncm91cE5hbWUgPSAoc2VsZWN0ZWRHcm91cCAmJiBzZWxlY3RlZEdyb3VwLm5hbWUgIT0gJycpID8gc2VsZWN0ZWRHcm91cC5uYW1lIDogdGhpcy5BTllfTEFCRUw7XG5cdFx0XHRsZXQgcm9vbU5hbWUgPSAodGhpcy5fc2VsZWN0ZWRSb29tKSA/IHRoaXMuX3NlbGVjdGVkUm9vbS5uYW1lIDogdGhpcy5BTllfTEFCRUw7XG5cblx0XHRcdHVzZXJTY29wZSA9IHRoaXMuX2dldFNjb3BlTGFiZWxQYXJ0KCdab25lOicsIHpvbmVOYW1lKSArICc8YnI+JyArIHRoaXMuX2dldFNjb3BlTGFiZWxQYXJ0KCdHcm91cDonLCBncm91cE5hbWUpICsgJzxicj4nICsgdGhpcy5fZ2V0U2NvcGVMYWJlbFBhcnQoJ1Jvb206Jywgcm9vbU5hbWUpO1xuXHRcdH1cblxuXHRcdCQoJyN6bm0tcm9vbVNjb3BlTGInKS5odG1sKHJvb21TY29wZSk7XG5cdFx0JCgnI3pubS11c2VyU2NvcGVMYicpLmh0bWwodXNlclNjb3BlKTtcblx0fVxuXG5cdF9nZXRTY29wZUxhYmVsUGFydChsYWJlbCwgdGV4dClcblx0e1xuXHRcdHJldHVybiBgPHNwYW4gY2xhc3M9XCJ0ZXh0LW11dGVkXCI+JHtsYWJlbH08L3NwYW4+IDxzcGFuPiR7dGV4dH08L3NwYW4+YDtcblx0fVxuXG5cdF9yZXNldFJvb21MaXN0KClcblx0e1xuXHRcdHRoaXMuX3Jvb21MaXN0Qm94LnNldERhdGFTb3VyY2UoW10pO1xuXG5cdFx0Ly8gQWxzbyBkaXNhYmxlIFJlbW92ZSBidXR0b25cblx0XHQkKCcjem5tLXJlbW92ZVJvb21CdCcpLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cdH1cblxuXHRfcmVzZXRVc2VyTGlzdCgpXG5cdHtcblx0XHR0aGlzLl91c2VyTGlzdEJveC5zZXREYXRhU291cmNlKFtdKTtcblx0fVxuXG5cdF9zZXRNYWluQ29udHJvbHNFbmFibGVkKClcblx0e1xuXHRcdGxldCBlbmFibGVkID0gKHRoaXMuX2FjdGl2ZVBhbmVsVHlwZSA9PSAnem9uZScgJiYgdGhpcy5fc2VsZWN0ZWRab25lICE9IHVuZGVmaW5lZClcblx0XHRcdFx0XHR8fCAodGhpcy5fYWN0aXZlUGFuZWxUeXBlID09ICdyb29tJyAmJiB0aGlzLl9zZWxlY3RlZFJvb20gIT0gdW5kZWZpbmVkKVxuXHRcdFx0XHRcdHx8ICh0aGlzLl9hY3RpdmVQYW5lbFR5cGUgPT0gJ3VzZXInICYmIHRoaXMuX3NlbGVjdGVkVXNlciAhPSB1bmRlZmluZWQpO1xuXG5cdFx0JCgnI3pubS1tYWluQ29udHJvbHMnKS5hdHRyKCdkaXNhYmxlZCcsICFlbmFibGVkKTtcblxuXHRcdCQoJyN6bm0tbW9uaXRvclRhcmdldExiJykudGV4dChlbmFibGVkID8gY2FwaXRhbGl6ZUZpcnN0KHRoaXMuX2FjdGl2ZVBhbmVsVHlwZSkgOiAnc2VsZWN0aW9uJyk7XG5cdFx0JCgnI3pubS1tZXNzYWdlSW4nKS5hdHRyKCdwbGFjZWhvbGRlcicsICdNZXNzYWdlIHRvICcgKyAoZW5hYmxlZCA/IGNhcGl0YWxpemVGaXJzdCh0aGlzLl9hY3RpdmVQYW5lbFR5cGUpIDogJ3NlbGVjdGlvbicpKTtcblx0fVxuXG5cdF9zaG93TGltaXRFeGNlZWRlZFdhcm5pbmcoaWNvbiwgdGl0bGUpXG5cdHtcblx0XHRpY29uLmF0dHIoJ3RpdGxlJywgdGl0bGUpO1xuXG5cdFx0aWYgKHRpdGxlICE9ICcnKVxuXHRcdFx0aWNvbi5yZW1vdmVDbGFzcygnaGlkZGVuJyk7XG5cdFx0ZWxzZVxuXHRcdFx0aWNvbi5hZGRDbGFzcygnaGlkZGVuJyk7XG5cdH1cblxuXHRfc2hvd1Jvb21DcmVhdGlvblBhbmVsKHJvb21TZXR0aW5ncylcblx0e1xuXHRcdC8vIEJ1aWxkIHVzZXIgaW50ZXJmYWNlIGJhc2VkIG9uIHBhc3NlZCBkYXRhXG5cdFx0dGhpcy5fcm9vbUNyZWF0aW9uSUJ1aWxkZXIuYnVpbGRJbnRlcmZhY2Uocm9vbVNldHRpbmdzLCAnem5tLXJvb21DcmVhdG9yVGFiTmF2JywgZmFsc2UsICdyYycpO1xuXG5cdFx0Ly8gRW5hYmxlIHNjcm9sbGluZyB0YWJzXG5cdFx0JCgnI3pubS1yb29tQ3JlYXRvclRhYk5hdiA+ICN0YWJzJykuc2Nyb2xsaW5nVGFicyh7XG5cdFx0XHRib290c3RyYXBWZXJzaW9uOiA0LFxuXHRcdFx0c2Nyb2xsVG9UYWJFZGdlOiB0cnVlLFxuXHRcdFx0ZW5hYmxlU3dpcGluZzogdHJ1ZSxcblx0XHRcdGRpc2FibGVTY3JvbGxBcnJvd3NPbkZ1bGx5U2Nyb2xsZWQ6IHRydWUsXG5cdFx0XHRjc3NDbGFzc0xlZnRBcnJvdzogJ2ZhIGZhLWNoZXZyb24tbGVmdCcsXG5cdFx0XHRjc3NDbGFzc1JpZ2h0QXJyb3c6ICdmYSBmYS1jaGV2cm9uLXJpZ2h0J1xuXHRcdH0pO1xuXG5cdFx0Ly8gUmVzZXQgTm90aWZ5IGNsaWVudHMgY2hlY2tib3hcblx0XHQkKCcjem5tLW5vdGlmeUNsaWVudHNDQicpLnByb3AoJ2NoZWNrZWQnLCB0cnVlKTtcblxuXHRcdC8vIFNldCBsaXN0ZW5lciBmb3IgY3VzdG9tIGFjdGlvbnMgdHJpZ2dlcmVkIGJ5IGNvbmZpZ3VyYXRpb24gaW50ZXJmYWNlXG5cdFx0JCgnI3pubS1yb29tQ3JlYXRvclRhYk5hdicpLm9uKCd2YWx1ZS1zZXQnLCAkLnByb3h5KHRoaXMuX29uQ29uZmlnVmFsdWVTZXQsIHRoaXMpKTtcblxuXHRcdC8vIERpc3BsYXkgcGFuZWxcblx0XHQkKCcjem5tLWNyZWF0ZVJvb21Nb2RhbCcpLm1vZGFsKCdzaG93Jyk7XG5cblx0XHQvLyBSZXNldCBhbmQgaGlkZSBlcnJvciBtZXNzYWdlXG5cdFx0dGhpcy5fcmVzZXRSb29tQ3JlYXRpb25FcnJvcigpO1xuXHR9XG5cblx0X3Jlc2V0Um9vbUNyZWF0aW9uRXJyb3IoKVxuXHR7XG5cdFx0Ly8gUmVzZXQgYW5kIGhpZGUgZXJyb3IgbWVzc2FnZVxuXHRcdCQoJyN6bm0tY3JlYXRlUm9vbUVycm9yJykudGV4dCgnJyk7XG5cdFx0JCgnI3pubS1jcmVhdGVSb29tRXJyb3InKS5oaWRlKCk7XG5cdH1cblxuXHRfdmFsaWRhdGVOZXdSb29tTmFtZShjaGFuZ2VzKVxuXHR7XG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBjaGFuZ2VzLnNpemUoKTsgaSsrKVxuXHRcdHtcblx0XHRcdGNvbnN0IHNldHRpbmcgPSBjaGFuZ2VzLmdldFNGU09iamVjdChpKTtcblxuXHRcdFx0aWYgKHNldHRpbmcuY29udGFpbnNLZXkoJ25hbWUnKSAmJiBzZXR0aW5nLmdldFV0ZlN0cmluZygnbmFtZScpID09ICduYW1lJylcblx0XHRcdHtcblx0XHRcdFx0Ly8gR2V0IG5hbWUgdmFsdWVcblx0XHRcdFx0Y29uc3QgbmFtZSA9IHNldHRpbmcuZ2V0VGV4dCgndmFsdWUnKTtcblxuXHRcdFx0XHQvLyBHZXQgZGF0YSBzb3VyY2Vcblx0XHRcdFx0Y29uc3QgZHMgPSB0aGlzLl9yb29tTGlzdEJveC5kYXRhU291cmNlLmRhdGEoKTtcblxuXHRcdFx0XHQvLyBDaGVjayBpZiBuYW1lIGV4aXN0cyBpbiBkYXRhIHNvdXJjZVxuXHRcdFx0XHRmb3IgKGxldCBqID0gMDsgaiA8IGRzLmxlbmd0aDsgaisrKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0aWYgKGRzW2pdLm5hbWUgPT0gbmFtZSlcblx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0X2VuYWJsZUNyZWF0ZVJvb21QYW5lbChlbmFibGUpXG5cdHtcblx0XHRsZXQgbW9kYWxFbGVtZW50ID0gJCgnI3pubS1jcmVhdGVSb29tTW9kYWwnKTtcblxuXHRcdC8vIEVuYWJsZSBtb2RhbCBjbG9zZSBidXR0b25zXG5cdFx0JCgnYnV0dG9uW2RhdGEtZGlzbWlzcz1cIm1vZGFsXCJdJywgbW9kYWxFbGVtZW50KS5hdHRyKCdkaXNhYmxlZCcsICFlbmFibGUpO1xuXG5cdFx0Ly8gRW5hYmxlIGNyZWF0ZSBidXR0b25cblx0XHQkKCcjem5tLXJvb21DcmVhdG9yQ3JlYXRlQnQnLCBtb2RhbEVsZW1lbnQpLmF0dHIoJ2Rpc2FibGVkJywgIWVuYWJsZSk7XG5cblx0XHQvLyBFbmFibGUgY2hlY2tib3hcblx0XHQkKCcjem5tLW5vdGlmeUNsaWVudHNDQicsIG1vZGFsRWxlbWVudCkuYXR0cignZGlzYWJsZWQnLCAhZW5hYmxlKTtcblxuXHRcdC8vIEVuYWJsZSBjb25maWd1cmF0aW9uIGludGVyZmFjZVxuXHRcdHRoaXMuX3Jvb21DcmVhdGlvbklCdWlsZGVyLmRpc2FibGVJbnRlcmZhY2UoIWVuYWJsZSk7XG5cdH1cblxuXHRfY2xlYXJUYWJzKG1vbml0b3JlZFR5cGUpXG5cdHtcblx0XHQvLyBEZXN0cm95IHNjcm9sbGluZyB0YWJzXG5cdFx0JChgI3pubS0ke21vbml0b3JlZFR5cGV9VGFiTmF2aWdhdG9yICN0YWJzYCkuc2Nyb2xsaW5nVGFicygnZGVzdHJveScpO1xuXG5cdFx0Ly8gUmVtb3ZlIGFsbCB0YWIgbmF2aWdhdG9yIGNvbnRlbnRcblx0XHR0aGlzLl9pbnRlcmZhY2VCdWlsZGVyLmRlc3Ryb3lJbnRlcmZhY2UoKTtcblxuXHRcdC8vIFNldCBhbGwgdGFiIHBhbmVscyBhcyBpbmFjdGl2ZVxuXHRcdCQoYCN6bm0tJHttb25pdG9yZWRUeXBlfVRhYk5hdmlnYXRvciAjdGFiUGFuZWxzIC50YWItcGFuZWApLnJlbW92ZUNsYXNzKCdzaG93IGFjdGl2ZScpO1xuXG5cdFx0Ly8gUmVtb3ZlIHRhYiBjaGFuZ2UgZXZlbnQgbGlzdGVuZXJcblx0XHQkKCdhW2RhdGEtdG9nZ2xlPVwidGFiXCJdJykub2ZmKCdzaG93bi5icy50YWInKTtcblxuXHRcdHRoaXMuX3NraXBJbml0VGFicyA9IGZhbHNlO1xuXHR9XG5cblx0X3Nob3dab25lVHJhZmZpY0RhdGEoZGF0YSlcblx0e1xuXHRcdC8vIEJ1aWxkIHVzZXIgY291bnQgbW9uaXRvciBoaXN0b3J5XG5cdFx0aWYgKGRhdGEuY29udGFpbnNLZXkoJ2hpc3RvcnknKSlcblx0XHR7XG5cdFx0XHRsZXQgdXNlckNvdW50RGF0YSA9IGRhdGEuZ2V0SW50QXJyYXkoJ2hpc3RvcnknKTtcblx0XHRcdGxldCBzYW1wbGluZ1JhdGVNaW5zID0gZGF0YS5nZXRJbnQoJ3JhdGUnKTtcblxuXHRcdFx0dGhpcy5fdXNlckNvdW50Q2hhcnQuYWRkSGlzdG9yeUVudHJpZXModXNlckNvdW50RGF0YSwgc2FtcGxpbmdSYXRlTWlucyAqIDYwKTtcblx0XHR9XG5cblx0XHQvLyBBZGQgbGFzdCB1c2VyIGNvdW50IHZhbHVlXG5cdFx0dGhpcy5fdXNlckNvdW50Q2hhcnQuYWRkRW50cnkoZGF0YS5nZXRJbnQoJ2N1cnJlbnQnKSk7XG5cdH1cblxuXHRfYWRkTG9nRW50cnlUb0dyaWQoZ3JpZCwgaXRlbSlcblx0e1xuXHRcdGxldCBkcyA9IGdyaWQuZGF0YVNvdXJjZTtcblxuXHRcdC8vIENoZWNrIGl0ZW1zIGxpbWl0XG5cdFx0aWYgKGRzLnRvdGFsKCkgPT0gdGhpcy5NQVhfRVhURU5TSU9OX0xPR19TSVpFKVxuXHRcdFx0ZHMucmVtb3ZlKGRzLmF0KDApKTtcblxuXHRcdGRzLmFkZChpdGVtKTtcblx0fVxuXG5cdF9zaG93VXNlclN0YXRzRGF0YShkYXRhKVxuXHR7XG5cdFx0Ly8gUGFja2V0IHF1ZXVlIGZpbGxpbmcgJVxuXHRcdGxldCBwYWNrZXRRdWV1ZSA9IHJvdW5kVG9EZWNpbWFscyhkYXRhLmdldEZsb2F0KCdwYWNrZXQnKSwgMik7XG5cdFx0dGhpcy5fcGFja2V0UXVldWVDaGFydC5zZXREYXRhU291cmNlKFt7Y2F0ZWdvcnk6ICdRdWV1ZScsIHZhbHVlOiBwYWNrZXRRdWV1ZX1dKTtcblxuXHRcdC8vIERyb3BwZWQgbWVzc2FnZXNcblx0XHRsZXQgZHJvcHBlZE1zZyA9IGRhdGEuZ2V0SW50KCdkcm9wcGVkJyk7XG5cdFx0dGhpcy5fZHJvcHBlZE1zZ0NoYXJ0LnNldERhdGFTb3VyY2UoW3tjYXRlZ29yeTogJ0Ryb3BwZWQnLCB2YWx1ZTogZHJvcHBlZE1zZ31dKTtcblxuXHRcdC8vIFdyaXR0ZW4gZGF0YSBhbW91bnRcblx0XHRsZXQgd3JpdHRlbkRhdGFPYmogPSBzY2FsZUJ5dGVzKGRhdGEuZ2V0TG9uZygnd0J5dGVzJyksIDIpO1xuXHRcdHRoaXMuX3dyaXR0ZW5EYXRhQ2hhcnQuc2V0RGF0YVNvdXJjZShbe2NhdGVnb3J5OiAnV3JpdHRlbicsIHZhbHVlOiB3cml0dGVuRGF0YU9iai52YWx1ZSwgdW5pdDogd3JpdHRlbkRhdGFPYmoudW5pdH1dKTtcblxuXHRcdC8vIFJlYWQgZGF0YSBhbW91bnRcblx0XHRsZXQgcmVhZERhdGFPYmogPSBzY2FsZUJ5dGVzKGRhdGEuZ2V0TG9uZygnckJ5dGVzJyksIDIpO1xuXHRcdHRoaXMuX3JlYWREYXRhQ2hhcnQuc2V0RGF0YVNvdXJjZShbe2NhdGVnb3J5OiAnUmVhZCcsIHZhbHVlOiByZWFkRGF0YU9iai52YWx1ZSwgdW5pdDogcmVhZERhdGFPYmoudW5pdH1dKTtcblx0fVxuXG5cdF9zZXRHZW9Mb2NhdGlvblVJKGdlb0xvY0RhdGEpXG5cdHtcblx0XHRjb25zdCBsb2NhdGlvbiA9IGdlb0xvY0RhdGEuZ2V0VXRmU3RyaW5nKCdsb2NhdGlvbicpO1xuXHRcdGNvbnN0IGVycm9yID0gZ2VvTG9jRGF0YS5nZXRVdGZTdHJpbmcoJ2Vycm9yJyk7XG5cdFx0Y29uc3QgbGF0aXR1ZGUgPSBnZW9Mb2NEYXRhLmdldFV0ZlN0cmluZygnbGF0aXR1ZGUnKTtcblx0XHRjb25zdCBsb25naXR1ZGUgPSBnZW9Mb2NEYXRhLmdldFV0ZlN0cmluZygnbG9uZ2l0dWRlJyk7XG5cblx0XHQvLyBTaG93IGxvY2F0aW9uXG5cdFx0JCgnI3pubS1nZW9Mb2NhdGlvbkxiJykudGV4dChsb2NhdGlvbik7XG5cblx0XHQvLyBMb2cgZXJyb3Jcblx0XHRpZiAoZXJyb3IgIT0gJycpXG5cdFx0XHR0aGlzLnNoZWxsQ3RybC5sb2dNZXNzYWdlKGVycm9yLCAnd2FybicpO1xuXG5cdFx0Ly8gRW5hYmxlL2Rpc2FibGUgU2hvdyBtYXAgYnV0dG9uXG5cdFx0aWYgKGxhdGl0dWRlICE9ICcnICYmIGxvbmdpdHVkZSAhPSAnJylcblx0XHR7XG5cdFx0XHQkKCcjem5tLXNob3dNYXBCdCcpLmF0dHIoJ2Rpc2FibGVkJywgZmFsc2UpO1xuXG5cdFx0XHRjb25zdCB1cmwgPSBgaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9tYXBzL3NlYXJjaC8/YXBpPTEmcXVlcnk9JHtOdW1iZXIobGF0aXR1ZGUpICsgJywnICsgTnVtYmVyKGxvbmdpdHVkZSl9YDtcblx0XHRcdCQoJyN6bm0tc2hvd01hcEJ0JykuYXR0cignaHJlZicsIHVybCk7XG5cdFx0fVxuXHR9XG5cblx0X2NsZWFyR2VvTG9jYXRpb25VSSgpXG5cdHtcblx0XHQkKCcjem5tLWdlb0xvY2F0aW9uTGInKS50ZXh0KCcnKTtcblx0XHQkKCcjem5tLXNob3dNYXBCdCcpLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cdFx0JCgnI3pubS1zaG93TWFwQnQnKS5hdHRyKCdocmVmJywgJyMnKTtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFBSSVZBVEUgR0VUVEVSU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdGdldCBfYWN0aXZlUGFuZWxUeXBlKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9hY2NvcmRpb24uc2VsZWN0KCkuZGF0YSgnaXRlbVR5cGUnKTtcblx0fVxuXG5cdGdldCBfc2VsZWN0ZWRab25lKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl96b25lTGlzdEJveC5kYXRhSXRlbSh0aGlzLl96b25lTGlzdEJveC5zZWxlY3QoKSk7XG5cdH1cblxuXHRnZXQgX3NlbGVjdGVkR3JvdXAoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2dyb3Vwc0Ryb3BEb3duLmRhdGFJdGVtKHRoaXMuX2dyb3Vwc0Ryb3BEb3duLnNlbGVjdCgpKTtcblx0fVxuXG5cdGdldCBfc2VsZWN0ZWRSb29tKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9yb29tTGlzdEJveC5kYXRhSXRlbSh0aGlzLl9yb29tTGlzdEJveC5zZWxlY3QoKSk7XG5cdH1cblxuXHRnZXQgX3NlbGVjdGVkVXNlcigpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fdXNlckxpc3RCb3guZGF0YUl0ZW0odGhpcy5fdXNlckxpc3RCb3guc2VsZWN0KCkpO1xuXHR9XG5cblx0Z2V0IF9pc0VkaXRpbmcoKVxuXHR7XG5cdFx0cmV0dXJuICh0aGlzLl9tb25pdG9yZWRUeXBlICE9IG51bGwgJiYgdGhpcy5fbW9uaXRvcmVkTmFtZSAhPSBudWxsICYmIHRoaXMuX2lzRWRpdE1vZGUpO1xuXHR9XG59XG4iLCJleHBvcnQgY2xhc3MgUm9vbVByb3BlcnRpZXNEYXRhXG57XG5cdHN0YXRpYyBnZXQgTEFCRUxTKCkge1xuXHRcdGxldCBtYXAgPSBuZXcgTWFwKCk7XG5cblx0XHRtYXAuc2V0KFNGUzJYLlJvb21Qcm9wZXJ0aWVzLk5BTUUsICduYW1lJyk7XG5cdFx0bWFwLnNldChTRlMyWC5Sb29tUHJvcGVydGllcy5HUk9VUF9JRCwgJ2dyb3VwSWQnKTtcblx0XHRtYXAuc2V0KFNGUzJYLlJvb21Qcm9wZXJ0aWVzLk1BWF9VU0VSUywgJ21heFVzZXJzJyk7XG5cdFx0bWFwLnNldChTRlMyWC5Sb29tUHJvcGVydGllcy5NQVhfU1BFQ1RBVE9SUywgJ21heFNwZWN0YXRvcnMnKTtcblx0XHRtYXAuc2V0KFNGUzJYLlJvb21Qcm9wZXJ0aWVzLlVTRVJfQ09VTlQsICd1c2VyQ291bnQnKTtcblx0XHRtYXAuc2V0KFNGUzJYLlJvb21Qcm9wZXJ0aWVzLlNQRUNUQVRPUl9DT1VOVCwgJ3NwZWN0YXRvckNvdW50Jyk7XG5cdFx0bWFwLnNldChTRlMyWC5Sb29tUHJvcGVydGllcy5JU19HQU1FLCAnaXNHYW1lJyk7XG5cdFx0bWFwLnNldChTRlMyWC5Sb29tUHJvcGVydGllcy5JU19QUklWQVRFLCAnaXNQcml2YXRlJyk7XG5cdFx0bWFwLnNldChTRlMyWC5Sb29tUHJvcGVydGllcy5IQVNfRlJFRV9QTEFZRVJfU0xPVFMsICdoYXNGcmVlUGxheWVyU2xvdHMnKTtcblx0XHRtYXAuc2V0KFNGUzJYLlJvb21Qcm9wZXJ0aWVzLklTX1RZUEVfU0ZTR0FNRSwgJ2lzU0ZTR2FtZVR5cGUnKTtcblxuXHRcdHJldHVybiBtYXA7XG5cdH1cblxuXHRzdGF0aWMgZ2V0TGFiZWwocHJvcE5hbWUpXG5cdHtcblx0XHRyZXR1cm4gJ1Jvb20uJyArIFJvb21Qcm9wZXJ0aWVzRGF0YS5MQUJFTFMuZ2V0KHByb3BOYW1lKTtcblx0fVxuXG5cdHN0YXRpYyBnZXQgcHJvcGVydGllc0FycmF5KClcblx0e1xuXHRcdGNvbnN0IGFyciA9IFtdO1xuXG5cdFx0Zm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgUm9vbVByb3BlcnRpZXNEYXRhLkxBQkVMUy5lbnRyaWVzKCkpXG5cdFx0e1xuXHRcdFx0YXJyLnB1c2goe1xuXHRcdFx0XHRsYWJlbDogUm9vbVByb3BlcnRpZXNEYXRhLmdldExhYmVsKGtleSksXG5cdFx0XHRcdHZhbHVlOiBrZXlcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdHJldHVybiBhcnI7XG5cdH1cbn1cblxuZXhwb3J0IGNsYXNzIFVzZXJQcm9wZXJ0aWVzRGF0YVxue1xuXHRzdGF0aWMgZ2V0IExBQkVMUygpIHtcblx0XHRsZXQgbWFwID0gbmV3IE1hcCgpO1xuXG5cdFx0bWFwLnNldChTRlMyWC5Vc2VyUHJvcGVydGllcy5OQU1FLCAnbmFtZScpO1xuXHRcdG1hcC5zZXQoU0ZTMlguVXNlclByb3BlcnRpZXMuSVNfUExBWUVSLCAnaXNQbGF5ZXInKTtcblx0XHRtYXAuc2V0KFNGUzJYLlVzZXJQcm9wZXJ0aWVzLklTX1NQRUNUQVRPUiwgJ2lzU3BlY3RhdG9yJyk7XG5cdFx0bWFwLnNldChTRlMyWC5Vc2VyUHJvcGVydGllcy5JU19OUEMsICdpc05QQycpO1xuXHRcdG1hcC5zZXQoU0ZTMlguVXNlclByb3BlcnRpZXMuUFJJVklMRUdFX0lELCAncHJpdmlsZWdlSWQnKTtcblxuXHRcdHJldHVybiBtYXA7XG5cdH1cblxuXHRzdGF0aWMgZ2V0TGFiZWwocHJvcE5hbWUpXG5cdHtcblx0XHRyZXR1cm4gJ1VzZXIuJyArIFVzZXJQcm9wZXJ0aWVzRGF0YS5MQUJFTFMuZ2V0KHByb3BOYW1lKTtcblx0fVxuXG5cdHN0YXRpYyBnZXQgcHJvcGVydGllc0FycmF5KClcblx0e1xuXHRcdGNvbnN0IGFyciA9IFtdO1xuXG5cdFx0Zm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgVXNlclByb3BlcnRpZXNEYXRhLkxBQkVMUy5lbnRyaWVzKCkpXG5cdFx0e1xuXHRcdFx0YXJyLnB1c2goe1xuXHRcdFx0XHRsYWJlbDogVXNlclByb3BlcnRpZXNEYXRhLmdldExhYmVsKGtleSksXG5cdFx0XHRcdHZhbHVlOiBrZXlcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdHJldHVybiBhcnI7XG5cdH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQzFKQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUNuS0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUN0YUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7OztBQ3ZIQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDOS9EQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBIiwic291cmNlUm9vdCI6IiJ9