rubyfox-server 2.13.6.1 → 2.16.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (575) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -1
  3. data/README.md +19 -0
  4. data/lib/rubyfox/server/cli.rb +39 -5
  5. data/lib/rubyfox/server/data/config/UploadsLock.txt +1 -1
  6. data/lib/rubyfox/server/data/config/admin/admintool.xml +1 -0
  7. data/lib/rubyfox/server/data/config/admin/descriptors/config_room.txt +97 -43
  8. data/lib/rubyfox/server/data/config/admin/descriptors/config_server.txt +307 -93
  9. data/lib/rubyfox/server/data/config/admin/descriptors/config_zone.txt +311 -95
  10. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_game.txt +5 -5
  11. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_mmo.txt +6 -6
  12. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_room.txt +69 -44
  13. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_user.txt +55 -43
  14. data/lib/rubyfox/server/data/config/admin/descriptors/runtime_zone.txt +81 -36
  15. data/lib/rubyfox/server/data/config/admin/gmc/gmc.py +55 -18
  16. data/lib/rubyfox/server/data/config/admin/icons/Analytics.png +0 -0
  17. data/lib/rubyfox/server/data/config/admin/icons/Analytics.svg +1 -0
  18. data/lib/rubyfox/server/data/config/admin/icons/BanManager.png +0 -0
  19. data/lib/rubyfox/server/data/config/admin/icons/BanManager.svg +1 -0
  20. data/lib/rubyfox/server/data/config/admin/icons/BlueBoxMonitor.png +0 -0
  21. data/lib/rubyfox/server/data/config/admin/icons/BlueBoxMonitor.svg +1 -0
  22. data/lib/rubyfox/server/data/config/admin/icons/Console.png +0 -0
  23. data/lib/rubyfox/server/data/config/admin/icons/Console.svg +9 -0
  24. data/lib/rubyfox/server/data/config/admin/icons/Dashboard.png +0 -0
  25. data/lib/rubyfox/server/data/config/admin/icons/Dashboard.svg +1 -0
  26. data/lib/rubyfox/server/data/config/admin/icons/ExtensionManager.png +0 -0
  27. data/lib/rubyfox/server/data/config/admin/icons/ExtensionManager.svg +1 -0
  28. data/lib/rubyfox/server/data/config/admin/icons/LicenseManager.png +0 -0
  29. data/lib/rubyfox/server/data/config/admin/icons/LicenseManager.svg +1 -0
  30. data/lib/rubyfox/server/data/config/admin/icons/LogViewer.png +0 -0
  31. data/lib/rubyfox/server/data/config/admin/icons/LogViewer.svg +1 -0
  32. data/lib/rubyfox/server/data/config/admin/icons/ServerConfigurator.png +0 -0
  33. data/lib/rubyfox/server/data/config/admin/icons/ServerConfigurator.svg +1 -0
  34. data/lib/rubyfox/server/data/config/admin/icons/ServletManager.svg +1 -0
  35. data/lib/rubyfox/server/data/config/admin/icons/ZoneConfigurator.png +0 -0
  36. data/lib/rubyfox/server/data/config/admin/icons/ZoneConfigurator.svg +1 -0
  37. data/lib/rubyfox/server/data/config/admin/icons/ZoneMonitor.png +0 -0
  38. data/lib/rubyfox/server/data/config/admin/icons/ZoneMonitor.svg +1 -0
  39. data/lib/rubyfox/server/data/config/core.xml +2 -2
  40. data/lib/rubyfox/server/data/config/log4j.properties +7 -7
  41. data/lib/rubyfox/server/data/config/server.xml +9 -10
  42. data/lib/rubyfox/server/data/config/wordsFile.txt +0 -2
  43. data/lib/rubyfox/server/data/data/GeoLite2-Country.mmdb +0 -0
  44. data/lib/rubyfox/server/data/{config → data/buddylists/BasicExamples}/.keep +0 -0
  45. data/lib/rubyfox/server/data/data/{buddylists → uploads}/.keep +0 -0
  46. data/lib/rubyfox/server/data/lib/BlueBox.war +0 -0
  47. data/lib/rubyfox/server/data/lib/apache-tomcat/LICENSE +1061 -0
  48. data/lib/rubyfox/server/data/lib/apache-tomcat/NOTICE +68 -0
  49. data/lib/rubyfox/server/data/lib/apache-tomcat/README.md +79 -0
  50. data/lib/rubyfox/server/data/lib/apache-tomcat/RELEASE-NOTES +174 -0
  51. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/bootstrap.jar +0 -0
  52. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/catalina-tasks.xml +39 -0
  53. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/catalina.bat +386 -0
  54. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/catalina.sh +689 -0
  55. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/ciphers.bat +58 -0
  56. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/ciphers.sh +60 -0
  57. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/commons-daemon-native.tar.gz +0 -0
  58. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/commons-daemon.jar +0 -0
  59. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/configtest.bat +58 -0
  60. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/configtest.sh +60 -0
  61. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/daemon.sh +293 -0
  62. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/digest.bat +58 -0
  63. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/digest.sh +60 -0
  64. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/makebase.bat +114 -0
  65. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/makebase.sh +115 -0
  66. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/setclasspath.bat +94 -0
  67. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/setclasspath.sh +98 -0
  68. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/shutdown.bat +58 -0
  69. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/shutdown.sh +60 -0
  70. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/startup.bat +58 -0
  71. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/startup.sh +60 -0
  72. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tomcat-juli.jar +0 -0
  73. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tomcat-native.tar.gz +0 -0
  74. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tool-wrapper.bat +110 -0
  75. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/tool-wrapper.sh +153 -0
  76. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/version.bat +58 -0
  77. data/lib/rubyfox/server/data/lib/apache-tomcat/bin/version.sh +60 -0
  78. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/Catalina/localhost/rewrite.config +1 -0
  79. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/catalina.policy +260 -0
  80. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/catalina.properties +206 -0
  81. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/context.xml +31 -0
  82. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/jaspic-providers.xml +23 -0
  83. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/jaspic-providers.xsd +53 -0
  84. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/keystore.jks +0 -0
  85. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/logging.properties +79 -0
  86. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/server.xml +161 -0
  87. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/tomcat-users.xml +41 -0
  88. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/tomcat-users.xsd +59 -0
  89. data/lib/rubyfox/server/data/lib/apache-tomcat/conf/web.xml +4733 -0
  90. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/annotations-api.jar +0 -0
  91. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ant.jar +0 -0
  92. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ha.jar +0 -0
  93. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-ssi.jar +0 -0
  94. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-storeconfig.jar +0 -0
  95. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina-tribes.jar +0 -0
  96. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/catalina.jar +0 -0
  97. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/ecj-4.15.jar +0 -0
  98. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/el-api.jar +0 -0
  99. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jasper-el.jar +0 -0
  100. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jasper.jar +0 -0
  101. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jaspic-api.jar +0 -0
  102. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/jsp-api.jar +0 -0
  103. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/servlet-api.jar +0 -0
  104. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/sfs2x-ws-helper.jar +0 -0
  105. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-api.jar +0 -0
  106. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-coyote.jar +0 -0
  107. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-dbcp.jar +0 -0
  108. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-cs.jar +0 -0
  109. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-de.jar +0 -0
  110. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-es.jar +0 -0
  111. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-fr.jar +0 -0
  112. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ja.jar +0 -0
  113. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ko.jar +0 -0
  114. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-pt-BR.jar +0 -0
  115. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-ru.jar +0 -0
  116. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-i18n-zh-CN.jar +0 -0
  117. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-jdbc.jar +0 -0
  118. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-jni.jar +0 -0
  119. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-util-scan.jar +0 -0
  120. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-util.jar +0 -0
  121. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/tomcat-websocket.jar +0 -0
  122. data/lib/rubyfox/server/data/lib/apache-tomcat/lib/websocket-api.jar +0 -0
  123. data/lib/rubyfox/server/data/{extensions → lib/apache-tomcat/logs}/.keep +0 -0
  124. data/lib/rubyfox/server/data/lib/{jetty/lib/ext/.donotdelete → apache-tomcat/temp/safeToDelete.tmp} +0 -0
  125. data/lib/rubyfox/server/data/lib/{jetty/resources → apache-tomcat/work}/.keep +0 -0
  126. data/lib/rubyfox/server/data/lib/commons-collections-3.2.2.jar +0 -0
  127. data/lib/rubyfox/server/data/lib/commons-compress-1.19.jar +0 -0
  128. data/lib/rubyfox/server/data/lib/js/LibApi.js +48 -181
  129. data/lib/rubyfox/server/data/lib/sfs2x-admin.jar +0 -0
  130. data/lib/rubyfox/server/data/lib/sfs2x-core.jar +0 -0
  131. data/lib/rubyfox/server/data/lib/sfs2x-lib.jar +0 -0
  132. data/lib/rubyfox/server/data/lib/sfs2x-util.jar +0 -0
  133. data/lib/rubyfox/server/data/lib/sfs2x.jar +0 -0
  134. data/lib/rubyfox/server/data/sfs2x-service +6 -6
  135. data/lib/rubyfox/server/data/sfs2x-service.vmoptions +1 -1
  136. data/lib/rubyfox/server/data/sfs2x.sh +1 -1
  137. data/lib/rubyfox/server/data/www/BlueBox.war +0 -0
  138. data/lib/rubyfox/server/data/www/HelloServlet/index.jsp +1 -1
  139. data/lib/rubyfox/server/data/www/{root → ROOT}/_css_/default.css +0 -0
  140. data/lib/rubyfox/server/data/www/{root → ROOT}/_css_/reset.css +0 -0
  141. data/lib/rubyfox/server/data/www/{root → ROOT}/_images_/background_gradient.png +0 -0
  142. data/lib/rubyfox/server/data/www/{root → ROOT}/_images_/background_logo.png +0 -0
  143. data/lib/rubyfox/server/data/www/{root → ROOT}/_images_/favicon.png +0 -0
  144. data/lib/rubyfox/server/data/www/{root → ROOT}/_images_/logo_smartfoxserver.png +0 -0
  145. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/_changes-to-default-themes_.txt +15 -0
  146. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/bootstrap.min.css +7 -0
  147. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/custom-bootstrap.min.css +1 -0
  148. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/css/all.min.css +5 -0
  149. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-brands-400.eot +0 -0
  150. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-brands-400.svg +3459 -0
  151. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  152. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-brands-400.woff +0 -0
  153. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  154. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-regular-400.eot +0 -0
  155. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-regular-400.svg +803 -0
  156. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  157. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-regular-400.woff +0 -0
  158. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  159. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-solid-900.eot +0 -0
  160. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-solid-900.svg +4527 -0
  161. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  162. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-solid-900.woff +0 -0
  163. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  164. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/fonts.css +175 -0
  165. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/jquery.scrolling-tabs.min.css +8 -0
  166. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/kendo.custom-bootstrap-v4.css +15280 -0
  167. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/reset.css +54 -0
  168. data/lib/rubyfox/server/data/www/ROOT/admin/assets/css/style.css +1428 -0
  169. data/lib/rubyfox/server/data/www/ROOT/admin/assets/data/countries.geo.json +178 -0
  170. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/FreeMono.otf +0 -0
  171. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/FreeMono.ttf +0 -0
  172. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/FreeMono.woff +0 -0
  173. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/FreeMono.woff2 +0 -0
  174. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-300.ttf +0 -0
  175. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-300.woff +0 -0
  176. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-300.woff2 +0 -0
  177. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-300italic.ttf +0 -0
  178. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-300italic.woff +0 -0
  179. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-300italic.woff2 +0 -0
  180. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-600.ttf +0 -0
  181. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-600.woff +0 -0
  182. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-600.woff2 +0 -0
  183. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-600italic.ttf +0 -0
  184. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-600italic.woff +0 -0
  185. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-600italic.woff2 +0 -0
  186. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-700.ttf +0 -0
  187. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-700.woff +0 -0
  188. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-700.woff2 +0 -0
  189. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-700italic.ttf +0 -0
  190. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-700italic.woff +0 -0
  191. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-700italic.woff2 +0 -0
  192. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-800.ttf +0 -0
  193. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-800.woff +0 -0
  194. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-800.woff2 +0 -0
  195. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-800italic.ttf +0 -0
  196. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-800italic.woff +0 -0
  197. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-800italic.woff2 +0 -0
  198. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-italic.ttf +0 -0
  199. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-italic.woff +0 -0
  200. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-italic.woff2 +0 -0
  201. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-regular.ttf +0 -0
  202. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-regular.woff +0 -0
  203. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/open-sans-v15-cyrillic_greek_cyrillic-ext_vietnamese_latin_latin-ext_greek-ext-regular.woff2 +0 -0
  204. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/roboto-condensed-v16-latin-300.ttf +0 -0
  205. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/roboto-condensed-v16-latin-300.woff +0 -0
  206. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/roboto-condensed-v16-latin-300.woff2 +0 -0
  207. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/roboto-condensed-v16-latin-700.ttf +0 -0
  208. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/roboto-condensed-v16-latin-700.woff +0 -0
  209. data/lib/rubyfox/server/data/www/ROOT/admin/assets/fonts/roboto-condensed-v16-latin-700.woff2 +0 -0
  210. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/compare.png +0 -0
  211. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/demographicsChart.png +0 -0
  212. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/demographicsCompare.png +0 -0
  213. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/demographicsFilter.png +0 -0
  214. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/demographicsMap.png +0 -0
  215. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/demographicsTable.png +0 -0
  216. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/technologyChart.png +0 -0
  217. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/technologyCompare.png +0 -0
  218. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/technologyFilter.png +0 -0
  219. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/analytics-adv/technologyTable.png +0 -0
  220. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/apple-touch-icon-180x180.png +0 -0
  221. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/favicon-16x16.png +0 -0
  222. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/favicon-32x32.png +0 -0
  223. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/favicon-64x64.png +0 -0
  224. data/lib/rubyfox/server/data/www/ROOT/admin/assets/images/logo.png +0 -0
  225. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/application.bundle.js +2208 -0
  226. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-0.bundle.js +7662 -0
  227. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-1.bundle.js +929 -0
  228. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-10.bundle.js +766 -0
  229. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-11.bundle.js +71 -0
  230. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12.bundle.js +1184 -0
  231. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-12~module-13~module-9.bundle.js +2618 -0
  232. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-13.bundle.js +3315 -0
  233. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-3.bundle.js +280 -0
  234. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-4.bundle.js +1122 -0
  235. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-5.bundle.js +2624 -0
  236. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-6.bundle.js +801 -0
  237. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-7.bundle.js +607 -0
  238. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-8.bundle.js +1221 -0
  239. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/module-9.bundle.js +847 -0
  240. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-0.bundle.js +3240 -0
  241. 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 +17357 -0
  242. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/core/modules/vendors~module-9.bundle.js +807 -0
  243. data/lib/rubyfox/server/data/{lib/jetty/webapps → www/ROOT/admin/assets/js/custom-modules}/.keep +0 -0
  244. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/libs/bootstrap.min.js +7 -0
  245. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/libs/jquery-3.3.1.min.js +2 -0
  246. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/libs/jquery.scrolling-tabs.min.js +8 -0
  247. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/libs/js.cookie.min.js +8 -0
  248. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/libs/kendo.all.min.js +136 -0
  249. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/libs/popper.min.js +5 -0
  250. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/libs/sfs2x-api-1.7.15.js +8 -0
  251. data/lib/rubyfox/server/data/www/ROOT/admin/assets/js/libs/versions-readme.txt +16 -0
  252. data/lib/rubyfox/server/data/www/ROOT/admin/index.html +244 -0
  253. data/lib/rubyfox/server/data/www/ROOT/admin/manifest.json +25 -0
  254. data/lib/rubyfox/server/data/www/ROOT/admin/modules/analytics.html +328 -0
  255. data/lib/rubyfox/server/data/www/ROOT/admin/modules/ban-manager.html +160 -0
  256. data/lib/rubyfox/server/data/www/ROOT/admin/modules/blue-box-monitor.html +37 -0
  257. data/lib/rubyfox/server/data/www/ROOT/admin/modules/console.html +135 -0
  258. data/lib/rubyfox/server/data/www/ROOT/admin/modules/dashboard.html +368 -0
  259. data/lib/rubyfox/server/data/www/ROOT/admin/modules/extension-manager.html +98 -0
  260. data/lib/rubyfox/server/data/www/ROOT/admin/modules/license-manager.html +117 -0
  261. data/lib/rubyfox/server/data/www/ROOT/admin/modules/log-viewer.html +194 -0
  262. data/lib/rubyfox/server/data/www/ROOT/admin/modules/server-configurator.html +55 -0
  263. data/lib/rubyfox/server/data/www/ROOT/admin/modules/servlet-manager.html +98 -0
  264. data/lib/rubyfox/server/data/www/ROOT/admin/modules/zone-configurator.html +62 -0
  265. data/lib/rubyfox/server/data/www/ROOT/admin/modules/zone-monitor.html +346 -0
  266. data/lib/rubyfox/server/data/www/{root → ROOT}/crossdomain.xml +0 -0
  267. data/lib/rubyfox/server/data/www/{root → ROOT}/examples/index.html +0 -0
  268. data/lib/rubyfox/server/data/www/{root → ROOT}/favicon.ico +0 -0
  269. data/lib/rubyfox/server/data/www/{root → ROOT}/favicon.png +0 -0
  270. data/lib/rubyfox/server/data/www/{root → ROOT}/index.html +0 -0
  271. data/lib/rubyfox/server/data/www/host-manager/META-INF/context.xml +24 -0
  272. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/jsp/401.jsp +71 -0
  273. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/jsp/403.jsp +90 -0
  274. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/jsp/404.jsp +62 -0
  275. data/lib/rubyfox/server/data/www/host-manager/WEB-INF/web.xml +131 -0
  276. data/lib/rubyfox/server/data/www/host-manager/images/asf-logo.svg +226 -0
  277. data/lib/rubyfox/server/data/www/host-manager/images/tomcat.gif +0 -0
  278. data/lib/rubyfox/server/data/www/host-manager/index.jsp +18 -0
  279. data/lib/rubyfox/server/data/www/host-manager/manager.xml +26 -0
  280. data/lib/rubyfox/server/data/{logs → www/logsBackup}/.keep +0 -0
  281. data/lib/rubyfox/server/data/www/manager/META-INF/context.xml +24 -0
  282. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/401.jsp +80 -0
  283. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/403.jsp +100 -0
  284. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/404.jsp +63 -0
  285. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorCerts.jsp +92 -0
  286. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorCiphers.jsp +92 -0
  287. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/connectorTrustedCerts.jsp +92 -0
  288. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/sessionDetail.jsp +197 -0
  289. data/lib/rubyfox/server/data/www/manager/WEB-INF/jsp/sessionsList.jsp +170 -0
  290. data/lib/rubyfox/server/data/www/manager/WEB-INF/web.xml +195 -0
  291. data/lib/rubyfox/server/data/www/manager/images/asf-logo.svg +226 -0
  292. data/lib/rubyfox/server/data/www/manager/images/tomcat.gif +0 -0
  293. data/lib/rubyfox/server/data/www/manager/index.jsp +18 -0
  294. data/lib/rubyfox/server/data/www/manager/status.xsd +84 -0
  295. data/lib/rubyfox/server/data/www/manager/xform.xsl +125 -0
  296. data/lib/rubyfox/server/version.rb +1 -1
  297. metadata +256 -299
  298. data/lib/rubyfox/server/data/config/ExtensionManagerLock.txt +0 -2
  299. data/lib/rubyfox/server/data/lib/Lib/reindex$py.class +0 -0
  300. data/lib/rubyfox/server/data/lib/jetty/VERSION.txt +0 -9320
  301. data/lib/rubyfox/server/data/lib/jetty/etc/README.spnego +0 -62
  302. data/lib/rubyfox/server/data/lib/jetty/etc/jamon.xml +0 -32
  303. data/lib/rubyfox/server/data/lib/jetty/etc/jdbcRealm.properties +0 -72
  304. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-alpn.xml +0 -32
  305. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-annotations.xml +0 -20
  306. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-cdi.xml +0 -19
  307. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-debug.xml +0 -36
  308. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-debuglog.xml +0 -25
  309. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-deploy.xml +0 -76
  310. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-gcloud-memcached-sessions.xml +0 -27
  311. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-gcloud-session-idmgr.xml +0 -19
  312. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-gcloud-sessions.xml +0 -27
  313. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-gzip.xml +0 -67
  314. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-http-forwarded.xml +0 -17
  315. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-http.xml +0 -47
  316. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-http2.xml +0 -26
  317. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-http2c.xml +0 -18
  318. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-https.xml +0 -29
  319. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-infinispan.xml +0 -39
  320. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-ipaccess.xml +0 -28
  321. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-jaas.xml +0 -16
  322. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-jdbc-sessions.xml +0 -34
  323. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-jmx-remote.xml +0 -40
  324. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-jmx.xml +0 -32
  325. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-logging.xml +0 -36
  326. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-lowresources.xml +0 -22
  327. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-monitor.xml +0 -30
  328. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-nosql.xml +0 -19
  329. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-plus.xml +0 -26
  330. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-proxy-protocol-ssl.xml +0 -10
  331. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-proxy-protocol.xml +0 -10
  332. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-proxy.xml +0 -35
  333. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-requestlog.xml +0 -30
  334. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-rewrite-customizer.xml +0 -17
  335. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-rewrite.xml +0 -31
  336. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-setuid.xml +0 -30
  337. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-spring.xml +0 -61
  338. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-ssl-context.xml +0 -29
  339. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-ssl.xml +0 -58
  340. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-started.xml +0 -15
  341. data/lib/rubyfox/server/data/lib/jetty/etc/jetty-stats.xml +0 -18
  342. data/lib/rubyfox/server/data/lib/jetty/etc/jetty.conf +0 -12
  343. data/lib/rubyfox/server/data/lib/jetty/etc/jetty.xml +0 -195
  344. data/lib/rubyfox/server/data/lib/jetty/etc/jminix.xml +0 -12
  345. data/lib/rubyfox/server/data/lib/jetty/etc/jolokia.xml +0 -16
  346. data/lib/rubyfox/server/data/lib/jetty/etc/keystore +0 -0
  347. data/lib/rubyfox/server/data/lib/jetty/etc/krb5.ini +0 -23
  348. data/lib/rubyfox/server/data/lib/jetty/etc/rewrite-compactpath.xml +0 -10
  349. data/lib/rubyfox/server/data/lib/jetty/etc/spnego.conf +0 -19
  350. data/lib/rubyfox/server/data/lib/jetty/etc/spnego.properties +0 -1
  351. data/lib/rubyfox/server/data/lib/jetty/etc/webdefault.xml +0 -539
  352. data/lib/rubyfox/server/data/lib/jetty/lib/asm-5.0.1.jar +0 -0
  353. data/lib/rubyfox/server/data/lib/jetty/lib/asm-commons-5.0.1.jar +0 -0
  354. data/lib/rubyfox/server/data/lib/jetty/lib/fcgi/fcgi-client-9.3.11.v20160721.jar +0 -0
  355. data/lib/rubyfox/server/data/lib/jetty/lib/fcgi/fcgi-server-9.3.11.v20160721.jar +0 -0
  356. data/lib/rubyfox/server/data/lib/jetty/lib/http2-common-9.3.11.v20160721.jar +0 -0
  357. data/lib/rubyfox/server/data/lib/jetty/lib/http2-hpack-9.3.11.v20160721.jar +0 -0
  358. data/lib/rubyfox/server/data/lib/jetty/lib/http2-server-9.3.11.v20160721.jar +0 -0
  359. data/lib/rubyfox/server/data/lib/jetty/lib/jaspi/javax.security.auth.message-1.0.0.v201108011116.jar +0 -0
  360. data/lib/rubyfox/server/data/lib/jetty/lib/javax-websocket-client-impl-9.3.11.v20160721.jar +0 -0
  361. data/lib/rubyfox/server/data/lib/jetty/lib/javax-websocket-server-impl-9.3.11.v20160721.jar +0 -0
  362. data/lib/rubyfox/server/data/lib/jetty/lib/javax.annotation-api-1.2.jar +0 -0
  363. data/lib/rubyfox/server/data/lib/jetty/lib/javax.websocket-api-1.0.jar +0 -0
  364. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-alpn-server-9.3.11.v20160721.jar +0 -0
  365. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-annotations-9.3.11.v20160721.jar +0 -0
  366. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-client-9.3.11.v20160721.jar +0 -0
  367. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-continuation-9.3.11.v20160721.jar +0 -0
  368. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-deploy-9.3.11.v20160721.jar +0 -0
  369. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-gcloud-memcached-session-manager-9.3.11.v20160721.jar +0 -0
  370. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-gcloud-session-manager-9.3.11.v20160721.jar +0 -0
  371. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-http-9.3.11.v20160721.jar +0 -0
  372. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-infinispan-9.3.11.v20160721.jar +0 -0
  373. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-io-9.3.11.v20160721.jar +0 -0
  374. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-jaas-9.3.11.v20160721.jar +0 -0
  375. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-jaspi-9.3.11.v20160721.jar +0 -0
  376. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-jmx-9.3.11.v20160721.jar +0 -0
  377. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-jndi-9.3.11.v20160721.jar +0 -0
  378. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-nosql-9.3.11.v20160721.jar +0 -0
  379. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-plus-9.3.11.v20160721.jar +0 -0
  380. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-proxy-9.3.11.v20160721.jar +0 -0
  381. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-quickstart-9.3.11.v20160721.jar +0 -0
  382. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-rewrite-9.3.11.v20160721.jar +0 -0
  383. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-schemas-3.1.jar +0 -0
  384. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-security-9.3.11.v20160721.jar +0 -0
  385. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-server-9.3.11.v20160721.jar +0 -0
  386. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-servlet-9.3.11.v20160721.jar +0 -0
  387. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-servlets-9.3.11.v20160721.jar +0 -0
  388. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-util-9.3.11.v20160721.jar +0 -0
  389. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-webapp-9.3.11.v20160721.jar +0 -0
  390. data/lib/rubyfox/server/data/lib/jetty/lib/jetty-xml-9.3.11.v20160721.jar +0 -0
  391. data/lib/rubyfox/server/data/lib/jetty/lib/jndi/javax.mail.glassfish-1.4.1.v201005082020.jar +0 -0
  392. data/lib/rubyfox/server/data/lib/jetty/lib/jndi/javax.transaction-api-1.2.jar +0 -0
  393. data/lib/rubyfox/server/data/lib/jetty/lib/monitor/jetty-monitor-9.3.11.v20160721.jar +0 -0
  394. data/lib/rubyfox/server/data/lib/jetty/lib/org.apache.taglibs.taglibs-standard-impl-1.2.5.jar +0 -0
  395. data/lib/rubyfox/server/data/lib/jetty/lib/org.apache.taglibs.taglibs-standard-spec-1.2.5.jar +0 -0
  396. data/lib/rubyfox/server/data/lib/jetty/lib/org.eclipse.jdt.core.compiler.ecj-4.4.2.jar +0 -0
  397. data/lib/rubyfox/server/data/lib/jetty/lib/org.eclipse.jetty.apache-jsp-9.3.11.v20160721.jar +0 -0
  398. data/lib/rubyfox/server/data/lib/jetty/lib/org.mortbay.jasper.apache-el-8.0.33.jar +0 -0
  399. data/lib/rubyfox/server/data/lib/jetty/lib/org.mortbay.jasper.apache-jsp-8.0.33.jar +0 -0
  400. data/lib/rubyfox/server/data/lib/jetty/lib/servlet-api-3.1.jar +0 -0
  401. data/lib/rubyfox/server/data/lib/jetty/lib/setuid/jetty-setuid-java-1.0.3.jar +0 -0
  402. data/lib/rubyfox/server/data/lib/jetty/lib/setuid/libsetuid-linux.so +0 -0
  403. data/lib/rubyfox/server/data/lib/jetty/lib/setuid/libsetuid-osx.so +0 -0
  404. data/lib/rubyfox/server/data/lib/jetty/lib/spring/jetty-spring-9.3.11.v20160721.jar +0 -0
  405. data/lib/rubyfox/server/data/lib/jetty/lib/start.jar +0 -0
  406. data/lib/rubyfox/server/data/lib/jetty/lib/websocket-api-9.3.11.v20160721.jar +0 -0
  407. data/lib/rubyfox/server/data/lib/jetty/lib/websocket-client-9.3.11.v20160721.jar +0 -0
  408. data/lib/rubyfox/server/data/lib/jetty/lib/websocket-common-9.3.11h.v20160721.jar +0 -0
  409. data/lib/rubyfox/server/data/lib/jetty/lib/websocket-server-9.3.11.v20160721.jar +0 -0
  410. data/lib/rubyfox/server/data/lib/jetty/lib/websocket-servlet-9.3.11.v20160721.jar +0 -0
  411. data/lib/rubyfox/server/data/lib/jetty/license-eplv10-aslv20.html +0 -576
  412. data/lib/rubyfox/server/data/lib/jetty/modules/.donotdelete +0 -0
  413. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0.mod +0 -8
  414. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_05.mod +0 -8
  415. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_101.mod +0 -8
  416. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_102.mod +0 -8
  417. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_11.mod +0 -8
  418. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_20.mod +0 -8
  419. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_25.mod +0 -8
  420. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_31.mod +0 -8
  421. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_40.mod +0 -8
  422. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_45.mod +0 -8
  423. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_51.mod +0 -8
  424. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_60.mod +0 -8
  425. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_65.mod +0 -8
  426. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_66.mod +0 -8
  427. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_71.mod +0 -8
  428. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_72.mod +0 -8
  429. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_73.mod +0 -8
  430. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_74.mod +0 -8
  431. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_77.mod +0 -8
  432. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_91.mod +0 -8
  433. data/lib/rubyfox/server/data/lib/jetty/modules/alpn-impl/alpn-1.8.0_92.mod +0 -8
  434. data/lib/rubyfox/server/data/lib/jetty/modules/alpn.mod +0 -53
  435. data/lib/rubyfox/server/data/lib/jetty/modules/annotations.mod +0 -17
  436. data/lib/rubyfox/server/data/lib/jetty/modules/apache-jsp.mod +0 -10
  437. data/lib/rubyfox/server/data/lib/jetty/modules/apache-jstl.mod +0 -9
  438. data/lib/rubyfox/server/data/lib/jetty/modules/cdi.mod +0 -39
  439. data/lib/rubyfox/server/data/lib/jetty/modules/client.mod +0 -6
  440. data/lib/rubyfox/server/data/lib/jetty/modules/continuation.mod +0 -6
  441. data/lib/rubyfox/server/data/lib/jetty/modules/debug.mod +0 -29
  442. data/lib/rubyfox/server/data/lib/jetty/modules/debuglog.mod +0 -25
  443. data/lib/rubyfox/server/data/lib/jetty/modules/deploy.mod +0 -31
  444. data/lib/rubyfox/server/data/lib/jetty/modules/ext.mod +0 -11
  445. data/lib/rubyfox/server/data/lib/jetty/modules/fcgi.mod +0 -15
  446. data/lib/rubyfox/server/data/lib/jetty/modules/gcloud-memcached-sessions.mod +0 -26
  447. data/lib/rubyfox/server/data/lib/jetty/modules/gcloud-session-idmgr.mod +0 -63
  448. data/lib/rubyfox/server/data/lib/jetty/modules/gcloud-sessions.mod +0 -11
  449. data/lib/rubyfox/server/data/lib/jetty/modules/gzip.mod +0 -23
  450. data/lib/rubyfox/server/data/lib/jetty/modules/hawtio.mod +0 -28
  451. data/lib/rubyfox/server/data/lib/jetty/modules/home-base-warning.mod +0 -7
  452. data/lib/rubyfox/server/data/lib/jetty/modules/http-forwarded.mod +0 -20
  453. data/lib/rubyfox/server/data/lib/jetty/modules/http.mod +0 -39
  454. data/lib/rubyfox/server/data/lib/jetty/modules/http2.mod +0 -20
  455. data/lib/rubyfox/server/data/lib/jetty/modules/http2c.mod +0 -22
  456. data/lib/rubyfox/server/data/lib/jetty/modules/https.mod +0 -14
  457. data/lib/rubyfox/server/data/lib/jetty/modules/infinispan.mod +0 -33
  458. data/lib/rubyfox/server/data/lib/jetty/modules/ipaccess.mod +0 -9
  459. data/lib/rubyfox/server/data/lib/jetty/modules/jaas.mod +0 -17
  460. data/lib/rubyfox/server/data/lib/jetty/modules/jamon.mod +0 -31
  461. data/lib/rubyfox/server/data/lib/jetty/modules/jaspi.mod +0 -10
  462. data/lib/rubyfox/server/data/lib/jetty/modules/jdbc-sessions.mod +0 -27
  463. data/lib/rubyfox/server/data/lib/jetty/modules/jminix.mod +0 -41
  464. data/lib/rubyfox/server/data/lib/jetty/modules/jmx-remote.mod +0 -16
  465. data/lib/rubyfox/server/data/lib/jetty/modules/jmx.mod +0 -13
  466. data/lib/rubyfox/server/data/lib/jetty/modules/jndi.mod +0 -11
  467. data/lib/rubyfox/server/data/lib/jetty/modules/jolokia.mod +0 -19
  468. data/lib/rubyfox/server/data/lib/jetty/modules/jsp.mod +0 -9
  469. data/lib/rubyfox/server/data/lib/jetty/modules/jstl.mod +0 -8
  470. data/lib/rubyfox/server/data/lib/jetty/modules/jvm.mod +0 -22
  471. data/lib/rubyfox/server/data/lib/jetty/modules/logging.mod +0 -36
  472. data/lib/rubyfox/server/data/lib/jetty/modules/lowresources.mod +0 -28
  473. data/lib/rubyfox/server/data/lib/jetty/modules/monitor.mod +0 -13
  474. data/lib/rubyfox/server/data/lib/jetty/modules/nosql.mod +0 -31
  475. data/lib/rubyfox/server/data/lib/jetty/modules/plus.mod +0 -15
  476. data/lib/rubyfox/server/data/lib/jetty/modules/proxy-protocol-ssl.mod +0 -9
  477. data/lib/rubyfox/server/data/lib/jetty/modules/proxy-protocol.mod +0 -9
  478. data/lib/rubyfox/server/data/lib/jetty/modules/proxy.mod +0 -22
  479. data/lib/rubyfox/server/data/lib/jetty/modules/quickstart.mod +0 -11
  480. data/lib/rubyfox/server/data/lib/jetty/modules/requestlog.mod +0 -40
  481. data/lib/rubyfox/server/data/lib/jetty/modules/resources.mod +0 -10
  482. data/lib/rubyfox/server/data/lib/jetty/modules/rewrite-compactpath.mod +0 -10
  483. data/lib/rubyfox/server/data/lib/jetty/modules/rewrite-customizer.mod +0 -24
  484. data/lib/rubyfox/server/data/lib/jetty/modules/rewrite.mod +0 -23
  485. data/lib/rubyfox/server/data/lib/jetty/modules/security.mod +0 -9
  486. data/lib/rubyfox/server/data/lib/jetty/modules/server.mod +0 -79
  487. data/lib/rubyfox/server/data/lib/jetty/modules/servlet.mod +0 -9
  488. data/lib/rubyfox/server/data/lib/jetty/modules/servlets.mod +0 -11
  489. data/lib/rubyfox/server/data/lib/jetty/modules/setuid.mod +0 -19
  490. data/lib/rubyfox/server/data/lib/jetty/modules/spring.mod +0 -17
  491. data/lib/rubyfox/server/data/lib/jetty/modules/ssl.mod +0 -97
  492. data/lib/rubyfox/server/data/lib/jetty/modules/stats.mod +0 -9
  493. data/lib/rubyfox/server/data/lib/jetty/modules/webapp.mod +0 -10
  494. data/lib/rubyfox/server/data/lib/jetty/modules/websocket.mod +0 -12
  495. data/lib/rubyfox/server/data/lib/jetty/notice.html +0 -111
  496. data/lib/rubyfox/server/data/lib/jetty/start.d/README.TXT +0 -24
  497. data/lib/rubyfox/server/data/lib/jetty/start.d/http.ini +0 -7
  498. data/lib/rubyfox/server/data/lib/jetty/start.d/https.ini +0 -10
  499. data/lib/rubyfox/server/data/lib/jetty/start.d/ssl.ini +0 -19
  500. data/lib/rubyfox/server/data/lib/jetty/start.ini +0 -83
  501. data/lib/rubyfox/server/data/www/.keep +0 -0
  502. data/lib/rubyfox/server/data/www/HelloServlet/META-INF/context.xml +0 -2
  503. data/lib/rubyfox/server/data/www/PyServletExample/MyModule$py.class +0 -0
  504. data/lib/rubyfox/server/data/www/PyServletExample/MyModule.py +0 -5
  505. data/lib/rubyfox/server/data/www/PyServletExample/WEB-INF/web.xml +0 -37
  506. data/lib/rubyfox/server/data/www/PyServletExample/errors/404.htm +0 -20
  507. data/lib/rubyfox/server/data/www/PyServletExample/index.py +0 -42
  508. data/lib/rubyfox/server/data/www/root/admin/.keep +0 -0
  509. data/lib/rubyfox/server/data/www/root/admin/AdminTool.swf +0 -0
  510. data/lib/rubyfox/server/data/www/root/admin/ReleaseNotes.txt +0 -201
  511. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/adobeFlashPlayer.png +0 -0
  512. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/advanced.png +0 -0
  513. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/analytics.png +0 -0
  514. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/banManager.png +0 -0
  515. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bannedIPs.png +0 -0
  516. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bannedUsernames.png +0 -0
  517. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bookmarks.png +0 -0
  518. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/bootLog.png +0 -0
  519. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/buddyList.png +0 -0
  520. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/buddyProperties.png +0 -0
  521. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/connection.png +0 -0
  522. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/databaseManager.png +0 -0
  523. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/floodFilter.png +0 -0
  524. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/gameSettings.png +0 -0
  525. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/general.png +0 -0
  526. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/globalServerStatus.png +0 -0
  527. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/hTML5WebSockets.png +0 -0
  528. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/iPDiscovery.png +0 -0
  529. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/iPFilter.png +0 -0
  530. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/jVMSettings.png +0 -0
  531. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/logsDownload.png +0 -0
  532. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/mMOSettings.png +0 -0
  533. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/mailer.png +0 -0
  534. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/permissionsAndEvents.png +0 -0
  535. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/privilegeManager.png +0 -0
  536. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/remoteAdmin.png +0 -0
  537. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomExtension.png +0 -0
  538. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomVariables.png +0 -0
  539. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/roomsAndGroups.png +0 -0
  540. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeLog.png +0 -0
  541. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeRoomSettings.png +0 -0
  542. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeUserSettings.png +0 -0
  543. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/runtimeZoneSettings.png +0 -0
  544. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/statsApplication.png +0 -0
  545. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/statsDemographics.png +0 -0
  546. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/statsExceptions.png +0 -0
  547. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/statsOverview.png +0 -0
  548. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/statsTechnology.png +0 -0
  549. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/systemQueueStatus.png +0 -0
  550. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/threadPools.png +0 -0
  551. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/userManagement.png +0 -0
  552. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/userVariables.png +0 -0
  553. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/webServer.png +0 -0
  554. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/wordsFilter.png +0 -0
  555. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/zoneExtension.png +0 -0
  556. data/lib/rubyfox/server/data/www/root/admin/assets/icons/tabs/zoneTraffic.png +0 -0
  557. data/lib/rubyfox/server/data/www/root/admin/expressInstall.swf +0 -0
  558. data/lib/rubyfox/server/data/www/root/admin/index.html +0 -124
  559. data/lib/rubyfox/server/data/www/root/admin/modules/Analytics.swf +0 -0
  560. data/lib/rubyfox/server/data/www/root/admin/modules/BanManager.swf +0 -0
  561. data/lib/rubyfox/server/data/www/root/admin/modules/BlueBoxMonitor.swf +0 -0
  562. data/lib/rubyfox/server/data/www/root/admin/modules/Console.swf +0 -0
  563. data/lib/rubyfox/server/data/www/root/admin/modules/Dashboard.swf +0 -0
  564. data/lib/rubyfox/server/data/www/root/admin/modules/ExtensionManager.swf +0 -0
  565. data/lib/rubyfox/server/data/www/root/admin/modules/LicenseManager.swf +0 -0
  566. data/lib/rubyfox/server/data/www/root/admin/modules/LogViewer.swf +0 -0
  567. data/lib/rubyfox/server/data/www/root/admin/modules/ServerConfigurator.swf +0 -0
  568. data/lib/rubyfox/server/data/www/root/admin/modules/ServletManager.swf +0 -0
  569. data/lib/rubyfox/server/data/www/root/admin/modules/ZoneConfigurator.swf +0 -0
  570. data/lib/rubyfox/server/data/www/root/admin/modules/ZoneMonitor.swf +0 -0
  571. data/lib/rubyfox/server/data/www/root/admin/swfobject.js +0 -4
  572. data/lib/rubyfox/server/data/www/root/examples/.keep +0 -0
  573. data/lib/rubyfox/server/data/www/sfs2x-ws.war +0 -0
  574. data/lib/rubyfox/server/data/www/sfs2x-ws.xml +0 -30
  575. data/lib/rubyfox/server/data/zones/BasicExamples.zone.xml +0 -147
@@ -0,0 +1,2618 @@
1
+ /*! (c) gotoAndPlay | All rights reserved */
2
+ (window["webpackJsonpapplication"] = window["webpackJsonpapplication"] || []).push([["module-12~module-13~module-9"],{
3
+
4
+ /***/ "./src/components/uibuilder/config-check-box.js":
5
+ /*!******************************************************!*\
6
+ !*** ./src/components/uibuilder/config-check-box.js ***!
7
+ \******************************************************/
8
+ /*! exports provided: ConfigCheckBox */
9
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
10
+
11
+ "use strict";
12
+ __webpack_require__.r(__webpack_exports__);
13
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigCheckBox", function() { return ConfigCheckBox; });
14
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
15
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
16
+
17
+
18
+
19
+ class ConfigCheckBox extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
20
+ {
21
+ constructor(configParam, editEnabled, inDialog)
22
+ {
23
+ super(configParam, editEnabled, inDialog);
24
+ }
25
+
26
+ /**
27
+ * Create widget to render the ConfigParameter value.
28
+ * If parameter is not editable, a simple label is used.
29
+ * @override
30
+ */
31
+ _generateInnerWidget()
32
+ {
33
+ if (this._data.editable)
34
+ {
35
+ // Set widget configuration
36
+ let config = {
37
+ type: 'checkbox',
38
+ class: '',
39
+ id: this._data.name,
40
+ name: this._data.name,
41
+ 'data-role': 'switch',
42
+ };
43
+
44
+ // Set widget attributes (see parent class)
45
+ this._setWidgetAttributes(config);
46
+
47
+ // Set additional widget attributes based on validation rules (see parent class)
48
+ this._setWidgetValidationAttributes(config);
49
+
50
+ // Create widget's html
51
+ this._widgetHtml = $('<input>', config);
52
+ }
53
+ else
54
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
55
+
56
+ // Return component
57
+ return this._widgetHtml;
58
+ }
59
+
60
+ /**
61
+ * Initialize widget.
62
+ * @override
63
+ */
64
+ _initialize()
65
+ {
66
+ if (this._data.editable)
67
+ {
68
+ // Initialize kendo widget
69
+ kendo.init(this._widgetHtml);
70
+
71
+ // Save ref. to widget
72
+ this._innerWidget = this._widgetHtml.data('kendoSwitch');
73
+
74
+ // Enable value commit binding
75
+ this._innerWidget.bind('change', $.proxy(this._onValueInput, this));
76
+ }
77
+
78
+ // Proceed with initialization
79
+ super._initialize();
80
+ }
81
+
82
+ /**
83
+ * Set widget's value.
84
+ * If parameter is not editable, the label text is set.
85
+ * @override
86
+ */
87
+ _setWidgetValue()
88
+ {
89
+ if (this._data.editable)
90
+ this._innerWidget.value(this._data.value);
91
+ else
92
+ this._widgetHtml.value = this._data.value;
93
+
94
+ // Trigger event
95
+ this._triggerEvent();
96
+ }
97
+
98
+ /**
99
+ * Set widget's disabled state.
100
+ * @override
101
+ */
102
+ _setWidgetEditEnabled()
103
+ {
104
+ if (this._data.editable)
105
+ this._innerWidget.enable(this._editEnabled);
106
+ }
107
+
108
+ /**
109
+ * Update Configuration Parameter value.
110
+ * @override
111
+ */
112
+ _onValueInput(e)
113
+ {
114
+ // Update Configuration Parameter to new value
115
+ this._data.value = this._innerWidget.value();
116
+
117
+ // Trigger event
118
+ this._triggerEvent();
119
+ }
120
+ }
121
+
122
+ // DEFINE COMPONENT
123
+ if (!window.customElements.get('config-check-box'))
124
+ window.customElements.define('config-check-box', ConfigCheckBox);
125
+
126
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
127
+
128
+ /***/ }),
129
+
130
+ /***/ "./src/components/uibuilder/config-drop-down-list.js":
131
+ /*!***********************************************************!*\
132
+ !*** ./src/components/uibuilder/config-drop-down-list.js ***!
133
+ \***********************************************************/
134
+ /*! exports provided: ConfigDropDownList */
135
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
136
+
137
+ "use strict";
138
+ __webpack_require__.r(__webpack_exports__);
139
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigDropDownList", function() { return ConfigDropDownList; });
140
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
141
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
142
+
143
+
144
+
145
+ class ConfigDropDownList extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
146
+ {
147
+ constructor(configParam, editEnabled, inDialog)
148
+ {
149
+ super(configParam, editEnabled, inDialog);
150
+ }
151
+
152
+ /**
153
+ * Create widget to render the ConfigParameter value.
154
+ * If parameter is not editable, a simple label is used.
155
+ * @override
156
+ */
157
+ _generateInnerWidget()
158
+ {
159
+ if (this._data.editable)
160
+ {
161
+ // Set widget configuration
162
+ let config = {
163
+ class: 'form-control',
164
+ id: this._data.name,
165
+ name: this._data.name,
166
+ 'data-role': 'dropdownlist',
167
+ };
168
+
169
+ // Set widget attributes (see parent class)
170
+ this._setWidgetAttributes(config);
171
+
172
+ // Set additional widget attributes based on validation rules (see parent class)
173
+ this._setWidgetValidationAttributes(config);
174
+
175
+ // Create widget's html
176
+ this._widgetHtml = $('<input>', config);
177
+ }
178
+ else
179
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
180
+
181
+ // Return component
182
+ return this._widgetHtml;
183
+ }
184
+
185
+ /**
186
+ * Initialize widget.
187
+ * @override
188
+ */
189
+ _initialize()
190
+ {
191
+ if (this._data.editable)
192
+ {
193
+ // Initialize kendo widget
194
+ kendo.init(this._widgetHtml);
195
+
196
+ // Save ref. to widget
197
+ this._innerWidget = this._widgetHtml.data('kendoDropDownList');
198
+
199
+ // Set list items
200
+ this._innerWidget.setDataSource(this._getDataSource(this._data.dataProvider))
201
+
202
+ // Enable value commit binding
203
+ this._widgetHtml.bind('change', $.proxy(this._onValueInput, this));
204
+ }
205
+
206
+ // Proceed with initialization
207
+ super._initialize();
208
+ }
209
+
210
+ /**
211
+ * Set widget's value.
212
+ * If parameter is not editable, the label text is set.
213
+ * @override
214
+ */
215
+ _setWidgetValue()
216
+ {
217
+ if (this._data.editable)
218
+ this._innerWidget.value(this._data.value);
219
+ else
220
+ this._widgetHtml.value = this._data.value;
221
+
222
+ // Trigger event
223
+ this._triggerEvent();
224
+ }
225
+
226
+ /**
227
+ * Set widget's disabled state.
228
+ * @override
229
+ */
230
+ _setWidgetEditEnabled()
231
+ {
232
+ if (this._data.editable)
233
+ this._innerWidget.wrapper.attr('disabled', !this._editEnabled);
234
+ }
235
+
236
+ /**
237
+ * Update Configuration Parameter value.
238
+ * @override
239
+ */
240
+ _onValueInput(e)
241
+ {
242
+ // Update Configuration Parameter to new value
243
+ this._data.value = this._innerWidget.value();
244
+
245
+ // Trigger event
246
+ this._triggerEvent();
247
+ }
248
+
249
+ _getDataSource(dpString)
250
+ {
251
+ if (dpString)
252
+ return dpString.split(',');
253
+
254
+ // In case the dataprovider is empty, add at least the current value
255
+ else
256
+ return [this._data.value];
257
+ }
258
+ }
259
+
260
+ // DEFINE COMPONENT
261
+ if (!window.customElements.get('config-drop-down-list'))
262
+ window.customElements.define('config-drop-down-list', ConfigDropDownList);
263
+
264
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
265
+
266
+ /***/ }),
267
+
268
+ /***/ "./src/components/uibuilder/config-dual-list.js":
269
+ /*!******************************************************!*\
270
+ !*** ./src/components/uibuilder/config-dual-list.js ***!
271
+ \******************************************************/
272
+ /*! exports provided: ConfigDualList */
273
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
274
+
275
+ "use strict";
276
+ __webpack_require__.r(__webpack_exports__);
277
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigDualList", function() { return ConfigDualList; });
278
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
279
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
280
+
281
+
282
+
283
+ class ConfigDualList extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
284
+ {
285
+ constructor(configParam, editEnabled, inDialog)
286
+ {
287
+ super(configParam, editEnabled, inDialog);
288
+ }
289
+
290
+ /**
291
+ * Create widget to render the ConfigParameter.
292
+ * @override
293
+ */
294
+ _generateInnerWidget()
295
+ {
296
+ this._widgetHtml = $('<div>');
297
+
298
+ const availableId = this._getId(this._data.name, 'available');
299
+ const selectedId = this._getId(this._data.name, 'selected');
300
+
301
+ // Create header for labels
302
+ let header = $('<div>', {class: 'form-label-container dual-list-labels'});
303
+
304
+ header.append($('<label>', {
305
+ class: 'font-italic form-label dual-list-left-col' + (!this._data.editable ? ' no-interact' : ''),
306
+ for: availableId,
307
+ }).text('Available'));
308
+
309
+ header.append($('<label>', {
310
+ class: 'font-italic font-weight-bold form-label dual-list-right-col' + (!this._data.editable ? ' no-interact' : ''),
311
+ for: selectedId,
312
+ }).text('Selected'));
313
+
314
+ this._widgetHtml.append(header);
315
+
316
+ // Add available items list
317
+ this._availableListHtml = $('<select>', {
318
+ id: availableId,
319
+ class: 'dual-list-left-col' + (!this._data.editable ? ' no-interact' : ''),
320
+ });
321
+ this._widgetHtml.append(this._availableListHtml);
322
+
323
+ // Add selected items list
324
+ this._selectedListHtml = $('<select>', {
325
+ id: selectedId,
326
+ class: 'dual-list-right-col' + (!this._data.editable ? ' no-interact' : ''),
327
+ });
328
+ this._widgetHtml.append(this._selectedListHtml);
329
+
330
+ // Return component
331
+ return this._widgetHtml;
332
+ }
333
+
334
+ // IDs containing a "." cause issues to connected lists
335
+ _getId(name, suffix)
336
+ {
337
+ return name.replace('.', '_') + '-' + suffix;
338
+ }
339
+
340
+ /**
341
+ * Initialize widget.
342
+ * @override
343
+ */
344
+ _initialize()
345
+ {
346
+ // Initialize "avalable" listbox
347
+ this._availableList = this._availableListHtml.kendoListBox({
348
+ connectWith: this._getId(this._data.name, 'selected'),
349
+ toolbar: {
350
+ tools: this._data.editable ? ['transferTo', 'transferFrom', 'transferAllTo', 'transferAllFrom'] : []
351
+ },
352
+ template: "<div>#:value#</div>",
353
+ selectable: 'multiple',
354
+ }).data('kendoListBox');
355
+
356
+ // Initialize "selected" listbox
357
+ this._selectedList = this._selectedListHtml.kendoListBox({
358
+ template: "<div>#:value#</div>",
359
+ selectable: 'multiple',
360
+ // The following listeners can't be used because events are fired before the datasource is actually updated
361
+ // We have to use a change event listener on the datasource (see below), even if not optimal
362
+ //add: $.proxy(this._onValueInput, this),
363
+ //remove: $.proxy(this._onValueInput, this),
364
+ }).data('kendoListBox');
365
+
366
+ // Proceed with initialization
367
+ super._initialize();
368
+ }
369
+
370
+ /**
371
+ * Set widget's datasource.
372
+ * @override
373
+ */
374
+ _setWidgetValue()
375
+ {
376
+ let availableArr = this._data.dataProvider != '' ? this._data.dataProvider.split(',') : [];
377
+ let selectedArr = this._data.value != '' ? this._data.value.split(',') : [];
378
+
379
+ // Remove selected values from available values
380
+ if (selectedArr.length > 0)
381
+ {
382
+ let temp = [];
383
+
384
+ for (let val of availableArr)
385
+ {
386
+ if (selectedArr.indexOf(val) == -1)
387
+ temp.push(val);
388
+ }
389
+
390
+ availableArr = temp;
391
+ }
392
+
393
+ // Convert lists of strings to lists of objects
394
+ let availableValues = [];
395
+ for (let val of availableArr)
396
+ availableValues.push({value: val});
397
+
398
+ let selectedValues = [];
399
+ for (let val of selectedArr)
400
+ selectedValues.push({value: val});
401
+
402
+ // Clear selection
403
+ this._availableList.clearSelection();
404
+ this._selectedList.clearSelection();
405
+
406
+ // Set datasources
407
+ this._availableList.setDataSource(new kendo.data.DataSource({
408
+ data: availableValues
409
+ }));
410
+
411
+ this._selectedList.setDataSource(new kendo.data.DataSource({
412
+ data: selectedValues,
413
+ // We listen to the change event instead of the add/remove events on the listbox, because those are fired before the datasource is updated
414
+ // This is not optimal because the event is fired for each item added to or removed from the datasource
415
+ change: $.proxy(this._onValueInput, this)
416
+ }));
417
+
418
+ // Disable editing
419
+ if (!this._data.editable)
420
+ {
421
+ this._availableList.enable('.k-item', false);
422
+ this._selectedList.enable('.k-item', false);
423
+ }
424
+
425
+ // Trigger event
426
+ this._triggerEvent();
427
+ }
428
+
429
+ /**
430
+ * Set widget's disabled state.
431
+ * @override
432
+ */
433
+ _setWidgetEditEnabled()
434
+ {
435
+ if (this._data.editable)
436
+ {
437
+ // Clear selection
438
+ this._availableList.clearSelection();
439
+ this._selectedList.clearSelection();
440
+
441
+ // Enable/disable lists
442
+ this._availableList.wrapper.attr('disabled', !this._editEnabled);
443
+ this._selectedList.wrapper.attr('disabled', !this._editEnabled);
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Update Configuration Parameter value.
449
+ * @override
450
+ */
451
+ _onValueInput(e)
452
+ {
453
+ let listData = this._selectedList.dataSource.data();
454
+
455
+ // Update Configuration Parameter to new value
456
+ this._data.value = listData.map(e => e.value).join(',');
457
+
458
+ // Trigger event
459
+ this._triggerEvent();
460
+ }
461
+ }
462
+
463
+ // DEFINE COMPONENT
464
+ if (!window.customElements.get('config-dual-list'))
465
+ window.customElements.define('config-dual-list', ConfigDualList);
466
+
467
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
468
+
469
+ /***/ }),
470
+
471
+ /***/ "./src/components/uibuilder/config-form-item.js":
472
+ /*!******************************************************!*\
473
+ !*** ./src/components/uibuilder/config-form-item.js ***!
474
+ \******************************************************/
475
+ /*! exports provided: ConfigFormItem */
476
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
477
+
478
+ "use strict";
479
+ __webpack_require__.r(__webpack_exports__);
480
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigFormItem", function() { return ConfigFormItem; });
481
+ class ConfigFormItem extends HTMLElement
482
+ {
483
+ constructor(configParam, editEnabled, inDialog)
484
+ {
485
+ super();
486
+
487
+ this.id = 'form-item-' + configParam.name;
488
+ this._editEnabled = editEnabled;
489
+ this._data = configParam;
490
+
491
+ // Create form item view
492
+ this._buildView(inDialog);
493
+
494
+ // Initialize form item
495
+ this._initialize();
496
+ }
497
+
498
+ connectedCallback()
499
+ {
500
+ // Trigger event
501
+ // NOTE: when a ConfigFormItem is instantiated, the _triggerEvent method is called as soon as its value is set.
502
+ // When this happenso, due to the fact that the object is not yet in the DOM, the event is not catched by the listener
503
+ // (which is attached to the outer container). So forcing the event to trigger again as soon as the ConfigFormItem
504
+ // is appended to the DOM is needed.
505
+ this._triggerEvent();
506
+ }
507
+
508
+ set data(configParam)
509
+ {
510
+ this._data = configParam;
511
+ this._setWidgetValue();
512
+ }
513
+
514
+ get data()
515
+ {
516
+ return this._data;
517
+ }
518
+
519
+ set editEnabled(enable)
520
+ {
521
+ if (enable != this._editEnabled)
522
+ {
523
+ this._editEnabled = enable;
524
+ this._setWidgetEditEnabled();
525
+ }
526
+ }
527
+
528
+ get editEnabled()
529
+ {
530
+ return this._editEnabled;
531
+ }
532
+
533
+ _buildView(isInsideDialog)
534
+ {
535
+ if (!isInsideDialog)
536
+ {
537
+ // Set additional classes for inner widget
538
+ let classNames = '';
539
+
540
+ switch (this._data.type)
541
+ {
542
+ case 'DualList':
543
+ classNames = 'col-sm-7 col-lg-8';
544
+ break;
545
+ case 'DataGrid':
546
+ classNames = 'col-sm'; // Use 'col-sm-7 col-lg-8' for DataGrid too?
547
+ break;
548
+ default:
549
+ classNames = 'col-sm-auto';
550
+
551
+ }
552
+
553
+ // Generate boilerplate html, surrounding the actual widget (label, numeric stepper, etc)
554
+ this.innerHTML = `
555
+ <div class="form-group position-relative row">
556
+ <div class="col-sm-5 col-lg-4 col-form-label form-label-container">
557
+ <label for="${this._data.name}" class="form-label ${(this._data.clientOnly ? 'client-only' : '')}">${this._data.label} <i class="fas fa-question-circle text-muted help" title="${this._data.tooltip}"></i></label>
558
+ </div>
559
+ <div class="inner-widget align-self-center ${classNames}">
560
+ <span class="k-invalid-msg" data-for="${this._data.name}"></span>
561
+ </div>
562
+ </div>
563
+ `;
564
+ }
565
+ else
566
+ {
567
+ this.innerHTML = `
568
+ <div class="form-group position-relative">
569
+ <div class="col-form-label form-label-container">
570
+ <label for="${this._data.name}" class="form-label ${(this._data.clientOnly ? 'client-only' : '')}">${this._data.label} <i class="fas fa-question-circle text-muted help" title="${this._data.tooltip}"></i></label>
571
+ </div>
572
+ <div class="inner-widget">
573
+ <span class="k-invalid-msg" data-for="${this._data.name}"></span>
574
+ </div>
575
+ </div>
576
+ `;
577
+ }
578
+
579
+ // Create inner widget (must be overridden)
580
+ let widget = this._generateInnerWidget();
581
+
582
+ // Append inner widget
583
+ $(this).find('.inner-widget').prepend(widget);
584
+ }
585
+
586
+ /**
587
+ * TO BE OVERRIDDEN
588
+ */
589
+ _generateInnerWidget()
590
+ {
591
+ // Show an error, should be overridden
592
+ console.error(`Unable to create ${this._data.type} form item for configuration parameter ${this.id}`);
593
+ }
594
+
595
+ /**
596
+ * Set attributes on the widget configuration object.
597
+ */
598
+ _setWidgetAttributes(config)
599
+ {
600
+ const attribs = this._data.attributes;
601
+
602
+ if (attribs)
603
+ {
604
+ for (let attr in attribs)
605
+ {
606
+ config[attr] = attribs[attr];
607
+
608
+ if (attr == 'pattern')
609
+ config['data-pattern-msg'] = 'Contains invalid characters';
610
+ }
611
+ }
612
+ }
613
+
614
+ /**
615
+ * Set additional attributes on the widget configuration object to properly validate input.
616
+ */
617
+ _setWidgetValidationAttributes(config)
618
+ {
619
+ const val = this._data.validator;
620
+
621
+ if (val != null && val != '')
622
+ {
623
+ if (val == 'ip')
624
+ {
625
+ config['pattern'] = '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$';
626
+ config['data-pattern-msg'] = 'Invalid IP address';
627
+ config['required'] = true;
628
+ config['data-required-msg'] = 'Required';
629
+ }
630
+
631
+ else if (val == 'notNull')
632
+ {
633
+ config['required'] = true;
634
+ config['data-required-msg'] = 'Required';
635
+ }
636
+
637
+ else if (val == 'pwd')
638
+ {
639
+ config['pattern'] = '^.{6,}$';
640
+ config['data-pattern-msg'] = 'Minimum length: 6 characters';
641
+ }
642
+
643
+ else if (val == 'posNum')
644
+ {
645
+ config['pattern'] = '^[0-9]\d*$';
646
+ config['data-pattern-msg'] = 'Non-negative number required';
647
+ }
648
+
649
+ else if (val == 'aoi')
650
+ {
651
+ // Nothing to do
652
+ // See Kendo validation initialization in config-interface-builder.js
653
+ }
654
+
655
+ else if (val == 'url')
656
+ {
657
+ config['type'] = 'url';
658
+ config['data-url-msg'] = 'Invalid URL';
659
+ }
660
+ }
661
+ }
662
+
663
+ /**
664
+ * Initialize form item.
665
+ *
666
+ * NOTE: must be overridden if inner widget requires special initialization (for example Kendo widgets)
667
+ */
668
+ _initialize()
669
+ {
670
+ // Set value
671
+ this._setWidgetValue();
672
+
673
+ // Set edit enabled
674
+ this._setWidgetEditEnabled();
675
+ }
676
+
677
+ /**
678
+ * TO BE OVERRIDDEN
679
+ */
680
+ _setWidgetValue()
681
+ {
682
+ // Nothing to do, must be overridden
683
+ }
684
+
685
+ /**
686
+ * TO BE OVERRIDDEN
687
+ */
688
+ _setWidgetEditEnabled()
689
+ {
690
+ // Nothing to do, must be overridden
691
+ }
692
+
693
+ /**
694
+ * TO BE OVERRIDDEN
695
+ */
696
+ _onValueInput(e)
697
+ {
698
+ // Nothing to do, must be overridden
699
+ }
700
+
701
+ _triggerEvent()
702
+ {
703
+ if (this._data.trigger)
704
+ {
705
+ let event = new CustomEvent('value-set', {detail: null, bubbles: true, cancelable: true});
706
+ this.dispatchEvent(event);
707
+ }
708
+ }
709
+ }
710
+
711
+ // DEFINE COMPONENT
712
+ if (!window.customElements.get('config-form-item'))
713
+ window.customElements.define('config-form-item', ConfigFormItem);
714
+
715
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
716
+
717
+ /***/ }),
718
+
719
+ /***/ "./src/components/uibuilder/config-grid.js":
720
+ /*!*************************************************!*\
721
+ !*** ./src/components/uibuilder/config-grid.js ***!
722
+ \*************************************************/
723
+ /*! exports provided: ConfigGrid */
724
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
725
+
726
+ "use strict";
727
+ __webpack_require__.r(__webpack_exports__);
728
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigGrid", function() { return ConfigGrid; });
729
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
730
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
731
+ /* harmony import */ var _widgets_list_item_editor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./widgets/list-item-editor */ "./src/components/uibuilder/widgets/list-item-editor.js");
732
+
733
+
734
+
735
+
736
+ class ConfigGrid extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
737
+ {
738
+ constructor(configParam, editEnabled, inDialog)
739
+ {
740
+ super(configParam, editEnabled, inDialog);
741
+ }
742
+
743
+ /**
744
+ * Create widget to render the ConfigParameter.
745
+ * @override
746
+ */
747
+ _generateInnerWidget()
748
+ {
749
+ // Create main widget's html
750
+ this._widgetHtml = $('<div>', {class: ''});
751
+
752
+ // Set grid widget configuration
753
+ let gridConfig = {
754
+ id: this._data.name,
755
+ name: this._data.name,
756
+ class: 'limited-height' + (!this._data.editable ? ' no-interact' : '')
757
+ };
758
+
759
+ // Append grid to main html; grid will be converted to Kendo widget during initialization
760
+ this._widgetHtml.append($('<div>', gridConfig));
761
+
762
+ if (this._data.editable)
763
+ {
764
+ // BUTTONS
765
+
766
+ // Create buttons container
767
+ let buttons = $('<div>', {class: 'mt-2 text-right'});
768
+
769
+ // Append buttons to container
770
+ this._addButton = $('<button>', {type: 'button', class: 'k-button k-secondary', title: 'Add'}).append($('<i class="fas fa-plus"></i>'));
771
+ this._editButton = $('<button>', {type: 'button', class: 'k-button k-secondary ml-2', title: 'Edit', disabled: true}).append($('<i class="fas fa-pen"></i>'));
772
+ this._removeButton = $('<button>', {type: 'button', class: 'k-button k-secondary ml-2', title: 'Remove', disabled: true}).append($('<i class="fas fa-times"></i>'));
773
+
774
+ buttons.append(this._addButton);
775
+ buttons.append(this._editButton);
776
+ buttons.append(this._removeButton);
777
+
778
+ // Append buttons container to main html
779
+ this._widgetHtml.append(buttons);
780
+
781
+ // Create edit dialog
782
+ // NOTE: data-dismiss="modal" on the close/cancel buttons was removed to work around an issue with nested modals;
783
+ // the custom "data-cancel" attribute is used to add a custom listener to the buttons
784
+ this._editDialog = $(`
785
+ <div class="modal" tabindex="-1" role="dialog" aria-labelledby="modalTitle" aria-hidden="true" data-keyboard="false" data-backdrop="static">
786
+ <div class="modal-dialog modal-dialog-centered" role="document">
787
+ <div class="modal-content">
788
+ <div class="modal-header">
789
+ <h5 class="modal-title text-primary" id="modalTitle">${this._data.label}</h5>
790
+ <button type="button" class="close" aria-label="Close" data-cancel="modal">
791
+ <span aria-hidden="true">&times;</span>
792
+ </button>
793
+ </div>
794
+ <div class="modal-body in-flow-invalid-msg">
795
+
796
+ </div>
797
+ <div class="modal-footer flex-column">
798
+ <div class="d-flex w-100">
799
+ <div class="flex-grow-1 text-left">
800
+ <button type="button" class="k-button k-primary">...</button>
801
+ </div>
802
+ <div class="flex-grow-1 text-right">
803
+ <button type="button" class="k-button k-secondary" data-cancel="modal">Cancel</button>
804
+ </div>
805
+ </div>
806
+ </div>
807
+ </div>
808
+ </div>
809
+ </div>
810
+ `);
811
+
812
+ // Add listener to dialog hide event
813
+ this._editDialog.on('hidden.bs.modal', $.proxy(this._onEditPanelHidden, this));
814
+
815
+ // Add listener to main button click event
816
+ $('button.k-primary', this._editDialog).on('click', $.proxy(this._onSubmitBtClick, this));
817
+
818
+ // Add listener to close/cancel buttons click event
819
+ $('button[data-cancel="modal"]', this._editDialog).on('click', $.proxy(this._onCancelBtClick, this));
820
+
821
+ // Append edit dialog to main html
822
+ this._widgetHtml.append(this._editDialog);
823
+ }
824
+
825
+ // Return component
826
+ return this._widgetHtml;
827
+ }
828
+
829
+ /**
830
+ * Initialize widget.
831
+ * @override
832
+ */
833
+ _initialize()
834
+ {
835
+ let columns = [];
836
+ for (let subConfigParam of this._data.defaultListItem)
837
+ {
838
+ let col = {
839
+ field: subConfigParam.name,
840
+ title: subConfigParam.label,
841
+ width: 120
842
+ }
843
+
844
+ // Display V or X for booleans
845
+ if (typeof subConfigParam.value === 'boolean')
846
+ col.template = `#= ${subConfigParam.name} ? '<i class="fas fa-check"></i>' : '<i class="fas fa-times"></i>' #`;
847
+
848
+ // Hide passwords
849
+ if (subConfigParam.type == 'TextInput' && subConfigParam.attributes != null && subConfigParam.attributes.type == 'password')
850
+ col.template = `#= '•'.repeat(data.${subConfigParam.name}.length) #`;
851
+
852
+ columns.push(col);
853
+ }
854
+
855
+ // Initialize grid
856
+ let gridHtml = this._widgetHtml.find(`#${$.escapeSelector(this._data.name)}`);
857
+
858
+ gridHtml.kendoGrid({
859
+ resizable: true,
860
+ selectable: this._data.editable ? 'row' : false,
861
+ change: $.proxy(this._onGridSelectionChange, this),
862
+ columns: columns,
863
+ noRecords: {
864
+ template: 'No items.'
865
+ }
866
+ });
867
+
868
+ // Save ref. to widget
869
+ this._gridWidget = gridHtml.data('kendoGrid');
870
+
871
+ // Show tootip if grid's cell content exceeds cell width (ellipsis is displayed by Kendo Grid)
872
+ gridHtml.kendoTooltip({
873
+ filter: 'td',
874
+ show: function(e) {
875
+ // Never show tooltip...
876
+ this.content.parent().css('visibility', 'hidden');
877
+
878
+ // ...unless content is returned (see below) due to cell width being exceeded
879
+ if (this.content.text() != '')
880
+ this.content.parent().css('visibility', 'visible');
881
+ },
882
+ hide: function() {
883
+ this.content.parent().css('visibility', 'hidden');
884
+ },
885
+ content: function(e) {
886
+ let element = e.target[0];
887
+ if (element.offsetWidth < element.scrollWidth)
888
+ return e.target.text();
889
+ else
890
+ return '';
891
+ }
892
+ });
893
+
894
+ /*
895
+ // Initialize button tooltips
896
+ this._widgetHtml.kendoTooltip({
897
+ filter: 'button',
898
+ content: function(e) {
899
+ return `<div class="help-tooltip">${e.target.data('title')}</div>`;
900
+ }
901
+ });
902
+ */
903
+
904
+ // Add button listeners
905
+ if (this._data.editable)
906
+ {
907
+ this._addButton.click($.proxy(this._onAddClick, this));
908
+ this._editButton.click($.proxy(this._onEditClick, this));
909
+ this._removeButton.click($.proxy(this._onRemoveClick, this));
910
+ }
911
+
912
+ // Proceed with initialization
913
+ super._initialize();
914
+ }
915
+
916
+ /**
917
+ * Set widget's datasource.
918
+ * @override
919
+ */
920
+ _setWidgetValue()
921
+ {
922
+ let dataSource = new kendo.data.DataSource({
923
+ data: this._data.listValues
924
+ });
925
+
926
+ // Read current horizontal scroll value
927
+ const scrollLeft = $('.k-grid-content', this._gridWidget.wrapper).scrollLeft();
928
+
929
+ // Clear grid selection if any
930
+ this._gridWidget.clearSelection();
931
+
932
+ // Set updated grid's datasource
933
+ this._gridWidget.setDataSource(dataSource);
934
+
935
+ // Set horizontal scroll
936
+ $('.k-grid-content', this._gridWidget.wrapper).scrollLeft(scrollLeft);
937
+ }
938
+
939
+ /**
940
+ * Set widget's disabled state.
941
+ * @override
942
+ */
943
+ _setWidgetEditEnabled()
944
+ {
945
+ if (this._data.editable)
946
+ {
947
+ // Deselect item
948
+ this._gridWidget.clearSelection();
949
+
950
+ // Enable/disable grid
951
+ this._gridWidget.wrapper.attr('disabled', !this._editEnabled);
952
+
953
+ // Enable "Add" button
954
+ if (this._editEnabled)
955
+ this._addButton.attr('disabled', false);
956
+
957
+ // Disable all buttons
958
+ else
959
+ {
960
+ this._addButton.attr('disabled', true);
961
+ this._editButton.attr('disabled', true);
962
+ this._removeButton.attr('disabled', true);
963
+ }
964
+ }
965
+ }
966
+
967
+ _onGridSelectionChange(e)
968
+ {
969
+ let selectedRows = this._gridWidget.select();
970
+ let selectedDataItems = [];
971
+
972
+ for (let i = 0; i < selectedRows.length; i++)
973
+ {
974
+ let dataItem = this._gridWidget.dataItem(selectedRows[i]);
975
+ selectedDataItems.push(dataItem);
976
+ }
977
+
978
+ // Enable/disable edit button
979
+ if (this._editButton)
980
+ this._editButton.prop('disabled', selectedDataItems.length == 0);
981
+
982
+ // Enable/disable remove button
983
+ if (this._removeButton)
984
+ this._removeButton.prop('disabled', selectedDataItems.length == 0);
985
+ }
986
+
987
+ _onRemoveClick()
988
+ {
989
+ let selectedIndex = this._gridWidget.select().index();
990
+
991
+ // Remove item from list
992
+ this._data.removeListItem(selectedIndex);
993
+
994
+ // Regenerate datagrid's datasource
995
+ this._setWidgetValue();
996
+ }
997
+
998
+ _onAddClick()
999
+ {
1000
+ // Clone default item and add to list
1001
+ let newListItem = [];
1002
+ for (let subCP of this._data.defaultListItem)
1003
+ newListItem.push(subCP.clone(true));
1004
+
1005
+ // Create edit popup
1006
+ this._openEditPanel(newListItem);
1007
+ }
1008
+
1009
+ _onEditClick()
1010
+ {
1011
+ let selectedIndex = this._gridWidget.select().index();
1012
+
1013
+ // Clone selected item and add to list
1014
+ let clonedListItem = [];
1015
+ for (let subCP of this._data.listItems[selectedIndex])
1016
+ clonedListItem.push(subCP.clone(true));
1017
+
1018
+ // Create edit popup
1019
+ this._openEditPanel(clonedListItem, selectedIndex);
1020
+ }
1021
+
1022
+ _openEditPanel(subConfigParamsArray, editIndex = -1)
1023
+ {
1024
+ // Check if this configuration item is inside a modal window;
1025
+ // if yes, the edit panel (which is a modal as well) must be configured to remove the dark background
1026
+ if ($(this).parents('.modal').length > 0)
1027
+ $('.modal', $(this)).attr('data-backdrop', false);
1028
+
1029
+ // Create dialog content
1030
+ this._itemEditor = new _widgets_list_item_editor__WEBPACK_IMPORTED_MODULE_2__["ListItemEditor"]();
1031
+ this._itemEditor.data = subConfigParamsArray;
1032
+ this._itemEditor.index = editIndex;
1033
+
1034
+ let itemEditor = $(this._itemEditor);
1035
+
1036
+ // Append content to dialog
1037
+ $('.modal-body', this._editDialog).append(itemEditor);
1038
+
1039
+ // Set dialog main button text
1040
+ $('button.k-primary', this._editDialog).html(editIndex > -1 ? '<i class="fas fa-pen mr-1"></i>Update' : '<i class="fas fa-plus mr-1"></i>Add');
1041
+
1042
+ // Display dialog
1043
+ this._editDialog.modal('show');
1044
+ }
1045
+
1046
+ _onSubmitBtClick()
1047
+ {
1048
+ if (this._itemEditor.validate())
1049
+ {
1050
+ let data = this._itemEditor.data;
1051
+ let index = this._itemEditor.index;
1052
+
1053
+ // Hide modal
1054
+ this._editDialog.modal('hide');
1055
+
1056
+ // Complete editing
1057
+ this._onEditComplete(data, index);
1058
+ }
1059
+ }
1060
+
1061
+ _onCancelBtClick()
1062
+ {
1063
+ // Hide modal
1064
+ this._editDialog.modal('hide');
1065
+ }
1066
+
1067
+ _onEditPanelHidden(e)
1068
+ {
1069
+ // Remove content from dialog
1070
+ this._itemEditor.remove();
1071
+
1072
+ // Set dialog main button text
1073
+ $('button.k-primary', this._editDialog).html('...');
1074
+
1075
+ this._itemEditor = null;
1076
+ }
1077
+
1078
+ _onEditComplete(listItem, editIndex)
1079
+ {
1080
+ // An existing list item was updated
1081
+ if (editIndex > -1)
1082
+ this._data.updateListItem(listItem, editIndex);
1083
+
1084
+ // A new list item was added; add it to the configuration parameter
1085
+ else
1086
+ this._data.addListItem(listItem);
1087
+
1088
+ // Regenerate datagrid's datasource
1089
+ this._setWidgetValue();
1090
+ }
1091
+ }
1092
+
1093
+ // DEFINE COMPONENT
1094
+ if (!window.customElements.get('config-grid'))
1095
+ window.customElements.define('config-grid', ConfigGrid);
1096
+
1097
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1098
+
1099
+ /***/ }),
1100
+
1101
+ /***/ "./src/components/uibuilder/config-label.js":
1102
+ /*!**************************************************!*\
1103
+ !*** ./src/components/uibuilder/config-label.js ***!
1104
+ \**************************************************/
1105
+ /*! exports provided: ConfigLabel */
1106
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1107
+
1108
+ "use strict";
1109
+ __webpack_require__.r(__webpack_exports__);
1110
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigLabel", function() { return ConfigLabel; });
1111
+ class ConfigLabel extends HTMLElement
1112
+ {
1113
+ constructor()
1114
+ {
1115
+ super();
1116
+
1117
+ this.setAttribute('class','config-label');
1118
+ }
1119
+
1120
+ set value(val)
1121
+ {
1122
+ if (typeof val === 'boolean')
1123
+ this.innerHTML = (val ? 'true' : 'false');
1124
+ else if (typeof val === 'number')
1125
+ this.innerHTML = (val ? val : 0);
1126
+ else
1127
+ this.innerHTML = (val != '' ? val : '&mdash;');
1128
+ }
1129
+
1130
+ get value()
1131
+ {
1132
+ return this.textContent;
1133
+ }
1134
+ }
1135
+
1136
+ // DEFINE COMPONENT
1137
+ if (!window.customElements.get('config-label'))
1138
+ window.customElements.define('config-label', ConfigLabel);
1139
+
1140
+
1141
+ /***/ }),
1142
+
1143
+ /***/ "./src/components/uibuilder/config-numeric-stepper.js":
1144
+ /*!************************************************************!*\
1145
+ !*** ./src/components/uibuilder/config-numeric-stepper.js ***!
1146
+ \************************************************************/
1147
+ /*! exports provided: ConfigNumericStepper */
1148
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1149
+
1150
+ "use strict";
1151
+ __webpack_require__.r(__webpack_exports__);
1152
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigNumericStepper", function() { return ConfigNumericStepper; });
1153
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1154
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1155
+
1156
+
1157
+
1158
+ class ConfigNumericStepper extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1159
+ {
1160
+ constructor(configParam, editEnabled, inDialog)
1161
+ {
1162
+ super(configParam, editEnabled, inDialog);
1163
+ }
1164
+
1165
+ /**
1166
+ * Create widget to render the ConfigParameter value.
1167
+ * If parameter is not editable, a simple label is used.
1168
+ * @override
1169
+ */
1170
+ _generateInnerWidget()
1171
+ {
1172
+ if (this._data.editable)
1173
+ {
1174
+ // Set widget configuration
1175
+ let config = {
1176
+ type: 'number',
1177
+ class: 'form-control',
1178
+ id: this._data.name,
1179
+ name: this._data.name,
1180
+ 'data-role': 'numerictextbox',
1181
+ 'data-required-msg': 'Required',
1182
+ 'data-format': '#',
1183
+ required: 'required',
1184
+ };
1185
+
1186
+ // Set widget attributes (see parent class)
1187
+ this._setWidgetAttributes(config);
1188
+
1189
+ // Set additional widget attributes based on validation rules (see parent class)
1190
+ this._setWidgetValidationAttributes(config);
1191
+
1192
+ // Create widget's html
1193
+ this._widgetHtml = $('<input>', config);
1194
+ }
1195
+ else
1196
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1197
+
1198
+ // Return component
1199
+ return this._widgetHtml;
1200
+ }
1201
+
1202
+ /**
1203
+ * Initialize widget.
1204
+ * @override
1205
+ */
1206
+ _initialize()
1207
+ {
1208
+ if (this._data.editable)
1209
+ {
1210
+ // Initialize kendo widget
1211
+ kendo.init(this._widgetHtml);
1212
+
1213
+ // Save ref. to widget
1214
+ this._innerWidget = this._widgetHtml.data('kendoNumericTextBox');
1215
+
1216
+ // Enable value commit binding
1217
+ this._innerWidget.bind('change', $.proxy(this._onValueInput, this));
1218
+ }
1219
+
1220
+ // Proceed with initialization
1221
+ super._initialize();
1222
+ }
1223
+
1224
+ /**
1225
+ * Set widget's value.
1226
+ * If parameter is not editable, the label text is set.
1227
+ * @override
1228
+ */
1229
+ _setWidgetValue()
1230
+ {
1231
+ if (this._data.editable)
1232
+ this._innerWidget.value(this._data.value);
1233
+ else
1234
+ this._widgetHtml.value = this._data.value;
1235
+
1236
+ // Trigger event
1237
+ this._triggerEvent();
1238
+ }
1239
+
1240
+ /**
1241
+ * Set widget's disabled state.
1242
+ * @override
1243
+ */
1244
+ _setWidgetEditEnabled()
1245
+ {
1246
+ if (this._data.editable)
1247
+ this._innerWidget.enable(this._editEnabled);
1248
+ }
1249
+
1250
+ /**
1251
+ * Update Configuration Parameter value.
1252
+ * @override
1253
+ */
1254
+ _onValueInput(e)
1255
+ {
1256
+ // Update Configuration Parameter to new value
1257
+ this._data.value = Number(this._innerWidget.value());
1258
+
1259
+ // Trigger event
1260
+ this._triggerEvent();
1261
+ }
1262
+ }
1263
+
1264
+ // DEFINE COMPONENT
1265
+ if (!window.customElements.get('config-numeric-stepper'))
1266
+ window.customElements.define('config-numeric-stepper', ConfigNumericStepper);
1267
+
1268
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1269
+
1270
+ /***/ }),
1271
+
1272
+ /***/ "./src/components/uibuilder/config-text-input.js":
1273
+ /*!*******************************************************!*\
1274
+ !*** ./src/components/uibuilder/config-text-input.js ***!
1275
+ \*******************************************************/
1276
+ /*! exports provided: ConfigTextInput */
1277
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1278
+
1279
+ "use strict";
1280
+ __webpack_require__.r(__webpack_exports__);
1281
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigTextInput", function() { return ConfigTextInput; });
1282
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1283
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1284
+
1285
+
1286
+
1287
+ class ConfigTextInput extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1288
+ {
1289
+ constructor(configParam, editEnabled, inDialog)
1290
+ {
1291
+ super(configParam, editEnabled, inDialog);
1292
+ }
1293
+
1294
+ /**
1295
+ * Create widget to render the ConfigParameter value.
1296
+ * If parameter is not editable, a simple label is used.
1297
+ * @override
1298
+ */
1299
+ _generateInnerWidget()
1300
+ {
1301
+ if (this._data.editable)
1302
+ {
1303
+ // Set widget configuration
1304
+ let config = {
1305
+ type: 'text',
1306
+ class: 'form-control k-textbox',
1307
+ id: this._data.name,
1308
+ name: this._data.name,
1309
+ autocomplete: 'off',
1310
+ };
1311
+
1312
+ // Set widget attributes
1313
+ this._setWidgetAttributes(config);
1314
+
1315
+ // Set additional widget attributes based on validation rules
1316
+ this._setWidgetValidationAttributes(config);
1317
+
1318
+ // Create widget's html
1319
+ this._widgetHtml = $('<input>', config);
1320
+
1321
+ // Enable value commit binding
1322
+ this._widgetHtml.on('change', $.proxy(this._onValueInput, this));
1323
+ }
1324
+ else
1325
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1326
+
1327
+ // Return component
1328
+ return this._widgetHtml;
1329
+ }
1330
+
1331
+ /**
1332
+ * Set widget's value.
1333
+ * If parameter is not editable, the label text is set.
1334
+ * @override
1335
+ */
1336
+ _setWidgetValue()
1337
+ {
1338
+ if (this._data.editable)
1339
+ this._widgetHtml.val(this._data.value);
1340
+ else
1341
+ this._widgetHtml.value = this._data.value;
1342
+
1343
+ // Trigger event
1344
+ this._triggerEvent();
1345
+ }
1346
+
1347
+ /**
1348
+ * Set widget's disabled state.
1349
+ * @override
1350
+ */
1351
+ _setWidgetEditEnabled()
1352
+ {
1353
+ if (this._data.editable)
1354
+ this._widgetHtml.attr('disabled', !this._editEnabled);
1355
+ }
1356
+
1357
+ /**
1358
+ * Update Configuration Parameter value.
1359
+ * @override
1360
+ */
1361
+ _onValueInput(e)
1362
+ {
1363
+ // Update Configuration Parameter to new value
1364
+ this._data.value = this._widgetHtml.val();
1365
+
1366
+ // Trigger event
1367
+ this._triggerEvent();
1368
+ }
1369
+ }
1370
+
1371
+ // DEFINE COMPONENT
1372
+ if (!window.customElements.get('config-text-input'))
1373
+ window.customElements.define('config-text-input', ConfigTextInput);
1374
+
1375
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1376
+
1377
+ /***/ }),
1378
+
1379
+ /***/ "./src/components/uibuilder/config-vector-3d.js":
1380
+ /*!******************************************************!*\
1381
+ !*** ./src/components/uibuilder/config-vector-3d.js ***!
1382
+ \******************************************************/
1383
+ /*! exports provided: ConfigVector3D */
1384
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1385
+
1386
+ "use strict";
1387
+ __webpack_require__.r(__webpack_exports__);
1388
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigVector3D", function() { return ConfigVector3D; });
1389
+ /* harmony import */ var _config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./config-form-item */ "./src/components/uibuilder/config-form-item.js");
1390
+ /* harmony import */ var _config_label__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-label */ "./src/components/uibuilder/config-label.js");
1391
+ /* harmony import */ var _widgets_vector_3d_input__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./widgets/vector-3d-input */ "./src/components/uibuilder/widgets/vector-3d-input.js");
1392
+
1393
+
1394
+
1395
+
1396
+ class ConfigVector3D extends _config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"]
1397
+ {
1398
+ constructor(configParam, editEnabled, inDialog)
1399
+ {
1400
+ super(configParam, editEnabled, inDialog);
1401
+ }
1402
+
1403
+ /**
1404
+ * Create widget to render the ConfigParameter value.
1405
+ * If parameter is not editable, a simple label is used.
1406
+ * @override
1407
+ */
1408
+ _generateInnerWidget()
1409
+ {
1410
+ if (this._data.editable)
1411
+ {
1412
+ // Create widget's html
1413
+ this._widgetHtml = new _widgets_vector_3d_input__WEBPACK_IMPORTED_MODULE_2__["Vector3DInput"](this._data.name, this._data.validator == 'aoi');
1414
+
1415
+ // Set widget attributes
1416
+ this._setWidgetAttributes(this._widgetHtml);
1417
+
1418
+ // Enable value commit binding
1419
+ $(this._widgetHtml).on('change', $.proxy(this._onValueInput, this));
1420
+ }
1421
+ else
1422
+ this._widgetHtml = new _config_label__WEBPACK_IMPORTED_MODULE_1__["ConfigLabel"]();
1423
+
1424
+ // Return component
1425
+ return this._widgetHtml;
1426
+ }
1427
+
1428
+ /**
1429
+ * Set widget's value.
1430
+ * If parameter is not editable, the label text is set.
1431
+ * @override
1432
+ */
1433
+ _setWidgetValue()
1434
+ {
1435
+ this._widgetHtml.value = this._data.value;
1436
+
1437
+ // Trigger event
1438
+ this._triggerEvent();
1439
+ }
1440
+
1441
+ /**
1442
+ * Set widget's disabled state.
1443
+ * @override
1444
+ */
1445
+ _setWidgetEditEnabled()
1446
+ {
1447
+ if (this._data.editable)
1448
+ {
1449
+ $(this._widgetHtml).attr('disabled', !this._editEnabled);
1450
+ }
1451
+ }
1452
+
1453
+ /**
1454
+ * Update Configuration Parameter value.
1455
+ * @override
1456
+ */
1457
+ _onValueInput(e)
1458
+ {
1459
+ // Update Configuration Parameter to new value
1460
+ this._data.value = this._widgetHtml.value;
1461
+
1462
+ // Trigger event
1463
+ this._triggerEvent();
1464
+ }
1465
+ }
1466
+
1467
+ // DEFINE COMPONENT
1468
+ if (!window.customElements.get('config-vector-3d'))
1469
+ window.customElements.define('config-vector-3d', ConfigVector3D);
1470
+
1471
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1472
+
1473
+ /***/ }),
1474
+
1475
+ /***/ "./src/components/uibuilder/widgets/list-item-editor.js":
1476
+ /*!**************************************************************!*\
1477
+ !*** ./src/components/uibuilder/widgets/list-item-editor.js ***!
1478
+ \**************************************************************/
1479
+ /*! exports provided: ListItemEditor */
1480
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1481
+
1482
+ "use strict";
1483
+ __webpack_require__.r(__webpack_exports__);
1484
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ListItemEditor", function() { return ListItemEditor; });
1485
+ /* harmony import */ var _utils_uibuilder_config_form_item_factory__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../utils/uibuilder/config-form-item-factory */ "./src/utils/uibuilder/config-form-item-factory.js");
1486
+
1487
+
1488
+ class ListItemEditor extends HTMLElement
1489
+ {
1490
+ constructor()
1491
+ {
1492
+ super();
1493
+ }
1494
+
1495
+ set data(subConfigParamsArray)
1496
+ {
1497
+ this._data = subConfigParamsArray;
1498
+
1499
+ this._buildView();
1500
+ }
1501
+
1502
+ get data()
1503
+ {
1504
+ return this._data;
1505
+ }
1506
+
1507
+ set index(index)
1508
+ {
1509
+ this._index = index;
1510
+ }
1511
+
1512
+ get index()
1513
+ {
1514
+ return this._index;
1515
+ }
1516
+
1517
+ _buildView()
1518
+ {
1519
+ // Generate container form
1520
+ this._form = $('<form>', {});
1521
+
1522
+ // Append form
1523
+ $(this).append(this._form);
1524
+
1525
+ // Generate form fields
1526
+ for (let configParam of this._data)
1527
+ {
1528
+ // Create form item
1529
+ let formItem = _utils_uibuilder_config_form_item_factory__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItemFactory"].create(configParam, true, true);
1530
+ formItem.data = configParam;
1531
+
1532
+ // Add form item to form
1533
+ this._form.append(formItem);
1534
+ }
1535
+
1536
+ // Initialize kendo validation on form
1537
+ this._validator = this._form.kendoValidator({
1538
+ validateOnBlur: true,
1539
+ rules: {
1540
+ // Add rule to validate AOI form items?
1541
+ // (see: https://demos.telerik.com/kendo-ui/validator/custom-validation)
1542
+ aoi: function (input) {
1543
+ if (input.is('[data-aoi-msg]') && input.val() != '')
1544
+ {
1545
+ if (input.val() == '0,0,0')
1546
+ return false;
1547
+ }
1548
+
1549
+ return true;
1550
+ }
1551
+ }
1552
+ }).data('kendoValidator');
1553
+ }
1554
+
1555
+ validate()
1556
+ {
1557
+ return this._validator.validate();
1558
+ }
1559
+ }
1560
+
1561
+ // DEFINE COMPONENT
1562
+ if (!window.customElements.get('list-item-editor'))
1563
+ window.customElements.define('list-item-editor', ListItemEditor);
1564
+
1565
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1566
+
1567
+ /***/ }),
1568
+
1569
+ /***/ "./src/components/uibuilder/widgets/vector-3d-input.js":
1570
+ /*!*************************************************************!*\
1571
+ !*** ./src/components/uibuilder/widgets/vector-3d-input.js ***!
1572
+ \*************************************************************/
1573
+ /*! exports provided: Vector3DInput */
1574
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1575
+
1576
+ "use strict";
1577
+ __webpack_require__.r(__webpack_exports__);
1578
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3DInput", function() { return Vector3DInput; });
1579
+ class Vector3DInput extends HTMLElement
1580
+ {
1581
+ constructor(id, isValidable)
1582
+ {
1583
+ super();
1584
+
1585
+ this.id = id;
1586
+ this.name = id;
1587
+
1588
+ this._isValidable = isValidable;
1589
+
1590
+ this._initialize();
1591
+ }
1592
+
1593
+ set enableClear(value)
1594
+ {
1595
+ if (value)
1596
+ this._clearButton.show();
1597
+ else
1598
+ this._clearButton.hide();
1599
+ }
1600
+
1601
+ set allowNegative(value)
1602
+ {
1603
+ if (value)
1604
+ {
1605
+ this._widgetX.setOptions( {min: null} );
1606
+ this._widgetY.setOptions( {min: null} );
1607
+ this._widgetZ.setOptions( {min: null} );
1608
+ }
1609
+ }
1610
+
1611
+ set value(val)
1612
+ {
1613
+ var coords = val.split(',');
1614
+
1615
+ if (coords.length >= 1)
1616
+ this._widgetX.value(coords[0]);
1617
+
1618
+ if (coords.length >= 2)
1619
+ this._widgetY.value(coords[1]);
1620
+
1621
+ if (coords.length >= 3)
1622
+ this._widgetZ.value(coords[2]);
1623
+
1624
+ if (this._isValidable)
1625
+ this._inputVal.val(this.value);
1626
+ }
1627
+
1628
+ get value()
1629
+ {
1630
+ if (this._widgetX.value() == null && this._widgetY.value() == null && this._widgetZ.value() == null)
1631
+ return '';
1632
+ else
1633
+ return this._widgetX.value() + ',' + this._widgetY.value() + ',' + this._widgetZ.value();
1634
+ }
1635
+
1636
+ _initialize()
1637
+ {
1638
+ // Generate container form
1639
+ this._container = $('<div>', {
1640
+ class: 'form-inline'
1641
+ });
1642
+
1643
+ // Append container
1644
+ $(this).append(this._container);
1645
+
1646
+ // Set inputs configuration
1647
+ let configHtml = {
1648
+ type: 'number',
1649
+ class: 'form-control short-4',
1650
+ };
1651
+
1652
+ // Set widget configuration
1653
+ let configWidget = {
1654
+ min: 0,
1655
+ spinners: false,
1656
+ format: '#.######',
1657
+ decimals: 6,
1658
+ round: false,
1659
+ spinners: false,
1660
+ restrictDecimals: false,
1661
+ change: $.proxy(this._onChange, this)
1662
+ };
1663
+
1664
+ // Create widgets
1665
+ this._inputX = $('<input>', configHtml);
1666
+ this._container.append(this._inputX);
1667
+ this._widgetX = this._inputX.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1668
+
1669
+ this._container.append('<span class="px-1">,</span>');
1670
+
1671
+ this._inputY = $('<input>', configHtml);
1672
+ this._container.append(this._inputY);
1673
+ this._widgetY = this._inputY.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1674
+
1675
+ this._container.append('<span class="px-1">,</span>');
1676
+
1677
+ this._inputZ = $('<input>', configHtml);
1678
+ this._container.append(this._inputZ);
1679
+ this._widgetZ = this._inputZ.kendoNumericTextBox(configWidget).data('kendoNumericTextBox');
1680
+
1681
+ this._container.append('<span class="px-1"></span>'); // Additional spacer
1682
+
1683
+ // Create invisible field to apply overall validation
1684
+ if (this._isValidable)
1685
+ {
1686
+ this._inputVal = $('<input>', {name: `${this.name}-custom-validate`, 'data-aoi-msg': 'Values can\'t all be 0'});
1687
+ this._container.append(this._inputVal);
1688
+ this._container.append(`<span class="k-invalid-msg" data-for="${this.name}-custom-validate"></span>`)
1689
+ this._inputVal.hide();
1690
+ }
1691
+
1692
+ // Create and append Clear button
1693
+ this._clearButton = $('<button>', {type: 'button', class: 'k-button k-secondary my-1', title: 'Clear'}).append($('<i class="fas fa-times"></i>'));
1694
+ this._clearButton.on('click', $.proxy(this._onClearClick, this));
1695
+ this._container.append(this._clearButton);
1696
+
1697
+ // Hide button by default
1698
+ this._clearButton.hide();
1699
+ }
1700
+
1701
+ _onChange()
1702
+ {
1703
+ // Empty strings are not allowed
1704
+ if (this._widgetX.value() == null)
1705
+ this._widgetX.value(0);
1706
+
1707
+ if (this._widgetY.value() == null)
1708
+ this._widgetY.value(0);
1709
+
1710
+ if (this._widgetZ.value() == null)
1711
+ this._widgetZ.value(0);
1712
+
1713
+ this._dispatchCommit();
1714
+ }
1715
+
1716
+ _onClearClick()
1717
+ {
1718
+ this._widgetX.value('');
1719
+ this._widgetY.value('');
1720
+ this._widgetZ.value('');
1721
+
1722
+ this._dispatchCommit();
1723
+ }
1724
+
1725
+ _dispatchCommit()
1726
+ {
1727
+ if (this._isValidable)
1728
+ this._inputVal.val(this.value);
1729
+
1730
+ this.dispatchEvent(new Event('change'));
1731
+ }
1732
+ }
1733
+
1734
+ // DEFINE COMPONENT
1735
+ if (!window.customElements.get('vector-3d-input'))
1736
+ window.customElements.define('vector-3d-input', Vector3DInput);
1737
+
1738
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
1739
+
1740
+ /***/ }),
1741
+
1742
+ /***/ "./src/utils/uibuilder/config-form-item-factory.js":
1743
+ /*!*********************************************************!*\
1744
+ !*** ./src/utils/uibuilder/config-form-item-factory.js ***!
1745
+ \*********************************************************/
1746
+ /*! exports provided: ConfigFormItemFactory */
1747
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1748
+
1749
+ "use strict";
1750
+ __webpack_require__.r(__webpack_exports__);
1751
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigFormItemFactory", function() { return ConfigFormItemFactory; });
1752
+ /* harmony import */ var _components_uibuilder_config_form_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../components/uibuilder/config-form-item */ "./src/components/uibuilder/config-form-item.js");
1753
+ /* harmony import */ var _components_uibuilder_config_numeric_stepper__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../components/uibuilder/config-numeric-stepper */ "./src/components/uibuilder/config-numeric-stepper.js");
1754
+ /* harmony import */ var _components_uibuilder_config_text_input__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../components/uibuilder/config-text-input */ "./src/components/uibuilder/config-text-input.js");
1755
+ /* harmony import */ var _components_uibuilder_config_check_box__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../components/uibuilder/config-check-box */ "./src/components/uibuilder/config-check-box.js");
1756
+ /* harmony import */ var _components_uibuilder_config_drop_down_list__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../components/uibuilder/config-drop-down-list */ "./src/components/uibuilder/config-drop-down-list.js");
1757
+ /* harmony import */ var _components_uibuilder_config_grid__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../components/uibuilder/config-grid */ "./src/components/uibuilder/config-grid.js");
1758
+ /* harmony import */ var _components_uibuilder_config_dual_list__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../components/uibuilder/config-dual-list */ "./src/components/uibuilder/config-dual-list.js");
1759
+ /* harmony import */ var _components_uibuilder_config_vector_3d__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../components/uibuilder/config-vector-3d */ "./src/components/uibuilder/config-vector-3d.js");
1760
+
1761
+
1762
+
1763
+
1764
+
1765
+
1766
+
1767
+
1768
+
1769
+
1770
+ class ConfigFormItemFactory
1771
+ {
1772
+ static create(configParam, editEnabled, inDialog = false)
1773
+ {
1774
+ switch (configParam.type)
1775
+ {
1776
+ case 'TextInput':
1777
+ return new _components_uibuilder_config_text_input__WEBPACK_IMPORTED_MODULE_2__["ConfigTextInput"](configParam, editEnabled, inDialog);
1778
+ break;
1779
+
1780
+ case 'CheckBox':
1781
+ return new _components_uibuilder_config_check_box__WEBPACK_IMPORTED_MODULE_3__["ConfigCheckBox"](configParam, editEnabled, inDialog);
1782
+ break;
1783
+
1784
+ case 'NumericStepper':
1785
+ return new _components_uibuilder_config_numeric_stepper__WEBPACK_IMPORTED_MODULE_1__["ConfigNumericStepper"](configParam, editEnabled, inDialog);
1786
+ break;
1787
+
1788
+ case 'ComboBox':
1789
+ return new _components_uibuilder_config_drop_down_list__WEBPACK_IMPORTED_MODULE_4__["ConfigDropDownList"](configParam, editEnabled, inDialog);
1790
+ break;
1791
+
1792
+ case 'DataGrid':
1793
+ return new _components_uibuilder_config_grid__WEBPACK_IMPORTED_MODULE_5__["ConfigGrid"](configParam, editEnabled, inDialog);
1794
+ break;
1795
+
1796
+ case 'DualList':
1797
+ return new _components_uibuilder_config_dual_list__WEBPACK_IMPORTED_MODULE_6__["ConfigDualList"](configParam, editEnabled, inDialog);
1798
+ break;
1799
+
1800
+ case 'Vector3D':
1801
+ return new _components_uibuilder_config_vector_3d__WEBPACK_IMPORTED_MODULE_7__["ConfigVector3D"](configParam, editEnabled, inDialog);
1802
+ break;
1803
+
1804
+ default:
1805
+ return new _components_uibuilder_config_form_item__WEBPACK_IMPORTED_MODULE_0__["ConfigFormItem"](configParam, editEnabled, inDialog); // Will log an error for missing form item type
1806
+ }
1807
+ }
1808
+ }
1809
+
1810
+
1811
+ /***/ }),
1812
+
1813
+ /***/ "./src/utils/uibuilder/config-interface-builder.js":
1814
+ /*!*********************************************************!*\
1815
+ !*** ./src/utils/uibuilder/config-interface-builder.js ***!
1816
+ \*********************************************************/
1817
+ /*! exports provided: ConfigInterfaceBuilder */
1818
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
1819
+
1820
+ "use strict";
1821
+ __webpack_require__.r(__webpack_exports__);
1822
+ /* WEBPACK VAR INJECTION */(function($) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigInterfaceBuilder", function() { return ConfigInterfaceBuilder; });
1823
+ /* harmony import */ var _configuration_parameter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./configuration-parameter */ "./src/utils/uibuilder/configuration-parameter.js");
1824
+ /* harmony import */ var _config_form_item_factory__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./config-form-item-factory */ "./src/utils/uibuilder/config-form-item-factory.js");
1825
+
1826
+
1827
+
1828
+ class ConfigInterfaceBuilder
1829
+ {
1830
+ constructor()
1831
+ {
1832
+ // Set some constants
1833
+ this.TAB_PREFIX = 'tab-'
1834
+ this.TAB_PANE_PREFIX = 'tabpane-';
1835
+ this.SEPARATOR_BEFORE = 'before';
1836
+ this.SEPARATOR_AFTER = 'after';
1837
+ }
1838
+
1839
+ dump(modifiedOnly = false)
1840
+ {
1841
+ let dumpStr = '';
1842
+
1843
+ for (let cp of this._configParams)
1844
+ {
1845
+ if (modifiedOnly)
1846
+ {
1847
+ if (cp.isModified)
1848
+ dumpStr += cp.toString() + '\n';
1849
+ }
1850
+ else
1851
+ dumpStr += cp.toString() + '\n';
1852
+ }
1853
+
1854
+ console.log(dumpStr);
1855
+ }
1856
+
1857
+ buildInterface(data, mainContainerId, disableEdit = false, tabSuffix = '')
1858
+ {
1859
+ this._mainContainerId = mainContainerId;
1860
+ this._configParams = new Array();
1861
+ this._validator = null;
1862
+
1863
+ let hasNewFormItem = false;
1864
+
1865
+ //console.log(data.getDump())
1866
+
1867
+ for (let i = 0; i < data.size(); i++)
1868
+ {
1869
+ // PARSE DATA
1870
+
1871
+ let configParam = _configuration_parameter__WEBPACK_IMPORTED_MODULE_0__["ConfigurationParameter"].fromSfsObject(data.get(i));
1872
+ this._configParams.push(configParam);
1873
+
1874
+ // Get tab and tab pane id from group id
1875
+ const tabId = this.TAB_PREFIX + configParam.categoryId + (tabSuffix ? '_' + tabSuffix : '');
1876
+ const tabPaneId = this.TAB_PANE_PREFIX + configParam.categoryId + (tabSuffix ? '_' + tabSuffix : '');
1877
+
1878
+ // BUILD INTERFACE :: TABS
1879
+
1880
+ // Check if a tab specific for this group already exists inside the mainContainer: if not, create it
1881
+ // (a tab already exists if it was created in a previous loop)
1882
+ let tab = $(`#${mainContainerId} > #tabs #${tabId}`);
1883
+
1884
+ if (tab.length == 0)
1885
+ {
1886
+ // Create tab for tab pane
1887
+ tab = $('<li>', {class: 'nav-item'});
1888
+ tab.append($('<a>', {
1889
+ class: 'nav-link' + (i == 0 ? ' active' : ''),
1890
+ id: tabId,
1891
+ 'data-toggle': 'tab',
1892
+ href: '#' + tabPaneId,
1893
+ role: 'tab',
1894
+ 'aria-controls': tabPaneId,
1895
+ 'aria-selected': (i == 0 ? 'true' : 'false'),
1896
+ html: configParam.category,
1897
+ }));
1898
+
1899
+ // Add tab to container
1900
+ $(`#${mainContainerId} > #tabs`).append(tab);
1901
+ }
1902
+
1903
+ // BUILD INTERFACE :: TAB PANES
1904
+
1905
+ // Check if a tab pane specific for this group already exists inside the mainContainer: if not, create it
1906
+ // (a tab pane already exists if it was created in a previous loop or if it exists statically in the html - in case it is needed to add some static content)
1907
+ let tabPane = $(`#${mainContainerId} > #tabPanels > #${tabPaneId}`);
1908
+
1909
+ if (tabPane.length == 0)
1910
+ {
1911
+ // Create tab pane
1912
+ tabPane = $('<div>', {
1913
+ class: 'tab-pane' + (i == 0 ? ' show active' : ''),
1914
+ id: tabPaneId,
1915
+ role: 'tabpanel',
1916
+ 'aria-labelledby': tabId,
1917
+ 'data-dynamic': 'true',
1918
+ });
1919
+
1920
+ // Add tab pane to container
1921
+ $(`#${mainContainerId} > #tabPanels`).append(tabPane);
1922
+ }
1923
+
1924
+ // BUILD INTERFACE :: TAB PANES' FORM
1925
+
1926
+ // Check if a form already exists inside the tab pane: if not, create it
1927
+ let form = tabPane.find('form');
1928
+
1929
+ if (form.length == 0)
1930
+ {
1931
+ // Create form
1932
+ form = $('<form>', {
1933
+ class: '',
1934
+ autocomplete: 'off'
1935
+ });
1936
+
1937
+ // Create an inner fieldset; this might be useful to easily disable the whole form at once (actually we don't use it because Kendo widgets are not disabled automatically)
1938
+ form.append(
1939
+ $('<fieldset>', {
1940
+ class: ''
1941
+ })
1942
+ );
1943
+
1944
+ // Add form to tab pane
1945
+ tabPane.prepend(form);
1946
+ }
1947
+
1948
+ // Get fieldset, which is the actual form items container
1949
+ let fieldset = form.find('fieldset');
1950
+
1951
+ // BUILD INTERFACE :: TAB PANES' FORM ITEMS
1952
+
1953
+ // Check if form item already exists in fieldset; if yes, just update its data
1954
+ let formItem = fieldset.find(`#form-item-${$.escapeSelector(configParam.name)}`);
1955
+
1956
+ if (formItem.length == 0)
1957
+ {
1958
+ hasNewFormItem = true;
1959
+
1960
+ formItem = _config_form_item_factory__WEBPACK_IMPORTED_MODULE_1__["ConfigFormItemFactory"].create(configParam, !disableEdit);
1961
+
1962
+ // Add separator before
1963
+ if (configParam.separator != null && configParam.separator.pos == 'before')
1964
+ fieldset.append(this._buildSeparator(configParam.separator));
1965
+
1966
+ // Add form item to form
1967
+ fieldset.append(formItem);
1968
+
1969
+ // Add separator after
1970
+ if (configParam.separator != null && configParam.separator.pos == 'after')
1971
+ fieldset.append(this._buildSeparator(configParam.separator));
1972
+ }
1973
+ else
1974
+ formItem[0].data = configParam;
1975
+ }
1976
+
1977
+ // Add listener to show help tooltips
1978
+ let allTabPanes = $(`#${mainContainerId} > #tabPanels > div.tab-pane`);
1979
+ allTabPanes.kendoTooltip({
1980
+ filter: 'i[title].help',
1981
+ position: 'right',
1982
+ width: '250px',
1983
+ content: function(e) {
1984
+ return `<div class="help-tooltip">${e.target.data('title')}</div>`;
1985
+ }
1986
+ });
1987
+
1988
+ // Initialize kendo validation on forms' main container
1989
+ this._validator = $(`#${mainContainerId}`).kendoValidator({
1990
+ validateOnBlur: true,
1991
+ rules: {
1992
+ // Add rule to validate AOI form items
1993
+ // (see: https://demos.telerik.com/kendo-ui/validator/custom-validation)
1994
+ aoi: function (input) {
1995
+ if (input.is('[data-aoi-msg]') && input.val() != '')
1996
+ {
1997
+ if (input.val() == '0,0,0')
1998
+ return false;
1999
+ }
2000
+
2001
+ return true;
2002
+ }
2003
+ }
2004
+ }).data('kendoValidator');
2005
+ }
2006
+
2007
+ destroyInterface()
2008
+ {
2009
+ // Destroy all Kendo widgets in forms
2010
+ kendo.destroy($(`#${this._mainContainerId} > #tabPanels > div.tab-pane > form`));
2011
+
2012
+ // Remove all tabs
2013
+ $(`#${this._mainContainerId} > #tabs`).empty();
2014
+
2015
+ // Remove dynamic tab panes (tab panes created by Interface Builder)
2016
+ $(`#${this._mainContainerId} > #tabPanels > div.tab-pane[data-dynamic="true"]`).remove();
2017
+
2018
+ // Remove form inside static tab panes (predefined tab panes in html)
2019
+ $(`#${this._mainContainerId} > #tabPanels > div.tab-pane > form`).remove();
2020
+ }
2021
+
2022
+ disableInterface(disable)
2023
+ {
2024
+ // Enable/disable all config form items
2025
+ $(`#${this._mainContainerId} *[id^='form-item-']`).prop('editEnabled', !disable);
2026
+ }
2027
+
2028
+ _buildSeparator(separator)
2029
+ {
2030
+ if (separator.text == null)
2031
+ return $(`<hr class="config-form-separator">`);
2032
+
2033
+ else
2034
+ return $(`<label class="config-form-separator-label mb-3">${separator.text}</label>`);
2035
+ }
2036
+
2037
+ getChangedData()
2038
+ {
2039
+ let changes = new SFS2X.SFSArray();
2040
+
2041
+ for (var cp of this._configParams)
2042
+ {
2043
+ if (cp.isModified)
2044
+ changes.addSFSObject(cp.toSfsObject());
2045
+ }
2046
+
2047
+ return changes;
2048
+ }
2049
+
2050
+ resetIsModified()
2051
+ {
2052
+ for (let cp of this._configParams)
2053
+ {
2054
+ if (cp.isModified)
2055
+ cp.resetIsModified();
2056
+ }
2057
+ }
2058
+
2059
+ checkIsValid()
2060
+ {
2061
+ return this._validator.validate();
2062
+ }
2063
+
2064
+ resetValidation()
2065
+ {
2066
+ this._validator.hideMessages();
2067
+
2068
+ // The method above doesn't remove the k-invalid classes and aria-invalid="true" attributes from inputs
2069
+ // Let's do it manually
2070
+ $(`#${this._mainContainerId} .k-invalid`).removeClass('k-invalid');
2071
+ $(`#${this._mainContainerId} [aria-invalid="true"]`).removeAttr('aria-invalid');
2072
+ }
2073
+
2074
+ getConfigFormItem(configParamName)
2075
+ {
2076
+ let formItem = $(`#${this._mainContainerId}`).find(`#form-item-${$.escapeSelector(configParamName)}`);
2077
+
2078
+ if (formItem.length > 0)
2079
+ return formItem[0];
2080
+ else
2081
+ return null;
2082
+ }
2083
+
2084
+ activateFirstTabPanel()
2085
+ {
2086
+ let configParam = this._configParams[0];
2087
+ const tabPaneId = this.TAB_PANE_PREFIX + configParam.categoryId;
2088
+ let tabPane = $(`#${this._mainContainerId} > #tabPanels > #${tabPaneId}`);
2089
+ tabPane.addClass('show active');
2090
+ }
2091
+ }
2092
+
2093
+ /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! jquery */ "jquery")))
2094
+
2095
+ /***/ }),
2096
+
2097
+ /***/ "./src/utils/uibuilder/configuration-parameter.js":
2098
+ /*!********************************************************!*\
2099
+ !*** ./src/utils/uibuilder/configuration-parameter.js ***!
2100
+ \********************************************************/
2101
+ /*! exports provided: ConfigurationParameter */
2102
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
2103
+
2104
+ "use strict";
2105
+ __webpack_require__.r(__webpack_exports__);
2106
+ /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConfigurationParameter", function() { return ConfigurationParameter; });
2107
+ class ConfigurationParameter
2108
+ {
2109
+ static fromSfsObject(element)
2110
+ {
2111
+ let cp = new ConfigurationParameter();
2112
+
2113
+ // Parse common data
2114
+ cp.name = element.getUtfString('name');
2115
+ cp.label = element.getUtfString('label');
2116
+ cp.category = element.getUtfString('category');
2117
+ cp.tooltip = element.getUtfString('tooltip');
2118
+ cp.type = element.getUtfString('type');
2119
+ cp.value = element.get('value');
2120
+ cp.validator = element.getUtfString('validator');
2121
+ cp.editable = (element.containsKey('edit') ? element.getBool('edit') : true);
2122
+ cp.trigger = (element.containsKey('trigger') ? element.getBool('trigger') : false);
2123
+ cp.triggerData = element.getSFSArray('triggerData');
2124
+ cp.clientOnly = (element.containsKey('clientOnly') ? element.getBool('clientOnly') : false);
2125
+ cp.dataProvider = element.getUtfString('dataProvider');
2126
+
2127
+ // Parse component specific attributes
2128
+ let tmpAttributes = element.getSFSObject('attributes');
2129
+ if (tmpAttributes != null)
2130
+ {
2131
+ let attributes = {};
2132
+
2133
+ let keys = tmpAttributes.getKeysArray();
2134
+ for (let key of keys)
2135
+ attributes[key] = tmpAttributes.get(key);
2136
+
2137
+ cp.attributes = attributes;
2138
+ }
2139
+
2140
+ // Parse separator settings
2141
+ let tmpSeparator = element.getSFSObject('separator');
2142
+ if (tmpSeparator != null)
2143
+ {
2144
+ let separator = {};
2145
+
2146
+ let keys1 = tmpSeparator.getKeysArray();
2147
+ for (let key1 of keys1)
2148
+ separator[key1] = tmpSeparator.get(key1);
2149
+
2150
+ cp.separator = separator;
2151
+ }
2152
+
2153
+ // Parse default list item
2154
+ let tmpDefaultListItem = element.getSFSArray('defaultListItem');
2155
+ if (tmpDefaultListItem != null && tmpDefaultListItem.size() > 0)
2156
+ {
2157
+ let defaultListItem = [];
2158
+
2159
+ for (let i = 0; i < tmpDefaultListItem.size(); i++)
2160
+ defaultListItem.push(ConfigurationParameter.fromSfsObject(tmpDefaultListItem.getSFSObject(i)));
2161
+
2162
+ cp.defaultListItem = defaultListItem;
2163
+
2164
+ // Parse list values
2165
+ let listValues = [];
2166
+
2167
+ let tmpListValues = element.getSFSArray('listValues');
2168
+ if (tmpListValues != null && tmpListValues.size() > 0)
2169
+ {
2170
+ for (let v = 0; v < tmpListValues.size(); v++)
2171
+ {
2172
+ let listValueObj = tmpListValues.getSFSObject(v);
2173
+ let obj = {};
2174
+
2175
+ let keys2 = listValueObj.getKeysArray();
2176
+ for (let key2 of keys2)
2177
+ obj[key2] = listValueObj.get(key2);
2178
+
2179
+ listValues.push(obj);
2180
+ }
2181
+ }
2182
+
2183
+ cp.listValues = listValues;
2184
+
2185
+ // If we have a list, on the server-side items could be represented by a class
2186
+ cp.clazz = element.getUtfString('clazz');
2187
+ }
2188
+
2189
+ return cp;
2190
+ }
2191
+
2192
+ constructor()
2193
+ {
2194
+ /* CONSTANTS */
2195
+ this.DEFAULT_CATEGORY_NAME = 'General';
2196
+ this.DEFAULT_CATEGORY_ID = 'general';
2197
+
2198
+ /* PUBLIC VARS */
2199
+
2200
+ this.name = '';
2201
+ this.label = '';
2202
+ this.tooltip = '';
2203
+ this.type = null;
2204
+ this.trigger = false;
2205
+ this.triggerData = null;
2206
+ this.clientOnly = false;
2207
+ this.editable = true;
2208
+ this.attributes = null;
2209
+ this.dataProvider = null;
2210
+
2211
+ this.separator = null; // Parameter used to create a separator before or after the config parameter
2212
+ this.defaultListItem = null; // List of sub-ConfigurationParameters, each containing the default values
2213
+ this.clazz = null; // Name of the class representing the list item (not used in case of primiteve data types)
2214
+
2215
+ /* PRIVATE VARS */
2216
+
2217
+ this._category = this.DEFAULT_CATEGORY_NAME;
2218
+ this._categoryId = this.DEFAULT_CATEGORY_ID;
2219
+ this._value = null;
2220
+ this._initialValue = null; // Save the initial value of the configuration parameter, to check if the value was modified
2221
+ this._validator = null;
2222
+
2223
+ this._listItems = []; // Array of arrays of ConfigurationParameters
2224
+ this._listItemsChanged = false; // Flag to be set in case a list item is added or removed
2225
+ }
2226
+
2227
+ //---------------------------------------------
2228
+ // GETTERS / SETTERS
2229
+ //---------------------------------------------
2230
+
2231
+ set category(val)
2232
+ {
2233
+ if (val)
2234
+ {
2235
+ this._category = val;
2236
+ this._setIdFromCategoryName(this._category);
2237
+ }
2238
+ }
2239
+
2240
+ get category()
2241
+ {
2242
+ return this._category;
2243
+ }
2244
+
2245
+ set value(val)
2246
+ {
2247
+ if (this._value != val)
2248
+ {
2249
+ // If value is null, then we are setting this for the first time and
2250
+ // we want to save the initial value, to check later if it has been modified
2251
+ if (this._value == null)
2252
+ this._initialValue = val;
2253
+
2254
+ this._value = val;
2255
+ }
2256
+ }
2257
+
2258
+ get value()
2259
+ {
2260
+ return this._value;
2261
+ }
2262
+
2263
+ set validator(val)
2264
+ {
2265
+ if (val)
2266
+ this._validator = val;
2267
+ }
2268
+
2269
+ get validator()
2270
+ {
2271
+ return this._validator;
2272
+ }
2273
+
2274
+ /**
2275
+ * An array of objects; each object contains the name-value pairs used to
2276
+ * populate the list of sub-configuration parameters arrays, based on defaultListItem.
2277
+ */
2278
+ set listValues(arr)
2279
+ {
2280
+ this._setSubConfigurationParams(arr);
2281
+ }
2282
+
2283
+ get listValues()
2284
+ {
2285
+ return this._getSubConfigurationParamsValues();
2286
+ }
2287
+
2288
+ //---------------------------------------------
2289
+ // GETTERS ONLY
2290
+ //---------------------------------------------
2291
+
2292
+ get isModified()
2293
+ {
2294
+ let _isModified = false;
2295
+
2296
+ // If the parameter is used on the client only (for example in a custom trigger)
2297
+ // then we never have to consider it as modified, to prevent it being sent to the server
2298
+ if (!this.clientOnly)
2299
+ {
2300
+ if (this._value != this._initialValue || this._listItemsChanged)
2301
+ _isModified = true;
2302
+ else
2303
+ {
2304
+ // Check sub parameters
2305
+ outerLoop: for (let listItem of this._listItems)
2306
+ {
2307
+ for (let subCP of listItem)
2308
+ {
2309
+ if (subCP.isModified)
2310
+ {
2311
+ _isModified = true;
2312
+ break outerLoop;
2313
+ }
2314
+ }
2315
+ }
2316
+ }
2317
+ }
2318
+
2319
+ return _isModified;
2320
+ }
2321
+
2322
+ get categoryId()
2323
+ {
2324
+ return this._categoryId;
2325
+ }
2326
+
2327
+ get listItems()
2328
+ {
2329
+ return this._listItems;
2330
+ }
2331
+
2332
+ //---------------------------------------------
2333
+ // PUBLIC METHODS
2334
+ //---------------------------------------------
2335
+
2336
+ /**
2337
+ * Return a clone of this ConfigurationParameter.
2338
+ */
2339
+ clone(cloneValue = false)
2340
+ {
2341
+ let cp = new ConfigurationParameter();
2342
+ cp.name = this.name;
2343
+ cp.label = this.label;
2344
+ cp.category = this.category;
2345
+ cp.tooltip = this.tooltip;
2346
+ cp.type = this.type;
2347
+ cp.validator = this.validator;
2348
+ cp.trigger = this.trigger;
2349
+ cp.triggerData = (this.triggerData != null ? SFS2X.SFSArray.newFromBinaryData(this.triggerData.toBinary()) : null);
2350
+ cp.clientOnly = this.clientOnly;
2351
+ cp.dataProvider = this.dataProvider;
2352
+
2353
+ if (cloneValue)
2354
+ cp.value = this.value;
2355
+
2356
+ if (this.attributes != null)
2357
+ {
2358
+ cp.attributes = new Object();
2359
+ for (let s1 in this.attributes)
2360
+ cp.attributes[s1] = this.attributes[s1];
2361
+ }
2362
+
2363
+ if (this.separator != null)
2364
+ {
2365
+ cp.separator = new Object()
2366
+ for (let s2 in this.separator)
2367
+ cp.separator[s2] = this.separator[s2];
2368
+ }
2369
+
2370
+ if (this.defaultListItem != null)
2371
+ {
2372
+ let clonedDefaultListItems = [];
2373
+
2374
+ for (let subCP of this.defaultListItem)
2375
+ clonedDefaultListItems.push(subCP.clone(cloneValue));
2376
+
2377
+ cp.defaultListItem = clonedDefaultListItems;
2378
+ }
2379
+
2380
+ cp.listValues = this.listValues; // No need to clone this, as the listValues setter already does it
2381
+ cp.clazz = this.clazz;
2382
+
2383
+ return cp;
2384
+ }
2385
+
2386
+ /**
2387
+ * Reset initial value by copying the current value.
2388
+ */
2389
+ resetIsModified()
2390
+ {
2391
+ this._initialValue = this._value;
2392
+
2393
+ // Reset sub-parameters
2394
+ if (this._listItems != null)
2395
+ {
2396
+ for (let listItem of this._listItems)
2397
+ {
2398
+ for (let subCP of listItem)
2399
+ subCP.resetIsModified();
2400
+ }
2401
+ }
2402
+
2403
+ this._listItemsChanged = false;
2404
+ }
2405
+
2406
+ addListItem(newListItem)
2407
+ {
2408
+ this._listItems.push(newListItem);
2409
+ this._listItemsChanged = true;
2410
+ }
2411
+
2412
+ updateListItem(listItem, itemIndex)
2413
+ {
2414
+ this._listItems[itemIndex] = listItem;
2415
+ this._listItemsChanged = true;
2416
+ }
2417
+
2418
+ removeListItem(itemIndex)
2419
+ {
2420
+ this._listItems.splice(itemIndex, 1);
2421
+ this._listItemsChanged = true;
2422
+ }
2423
+
2424
+ toSfsObject()
2425
+ {
2426
+ let obj = new SFS2X.SFSObject();
2427
+
2428
+ // Set changed setting name
2429
+ obj.putUtfString('name', this.name);
2430
+
2431
+ // Set changed setting class, if any
2432
+ if (this.clazz != null)
2433
+ obj.putUtfString('clazz', this.clazz);
2434
+
2435
+ if (this.value != null)
2436
+ {
2437
+ // Set changed setting value
2438
+ if (typeof this.value === 'boolean')
2439
+ obj.putBool('value', this.value);
2440
+ else if (typeof this.value === 'number')
2441
+ obj.putInt('value', this.value);
2442
+ else
2443
+ obj.putText('value', this.value);
2444
+ }
2445
+ else
2446
+ {
2447
+ // Set changed setting list of values
2448
+
2449
+ let listItems = new SFS2X.SFSArray();
2450
+
2451
+ for (let a of this._listItems)
2452
+ {
2453
+ if (a.length == 1) // We have just one sub config param; no need to parse it complitely
2454
+ {
2455
+ // Simple list
2456
+ let tempObj = a[0].toSfsObject();
2457
+ let wa = tempObj.getWrappedItem('value');
2458
+ listItems.add(wa.value, wa.type);
2459
+ }
2460
+ else
2461
+ {
2462
+ // Complex list
2463
+
2464
+ let values = new SFS2X.SFSArray();
2465
+
2466
+ for (let subCp of a)
2467
+ values.addSFSObject(subCp.toSfsObject());
2468
+
2469
+ listItems.addSFSArray(values);
2470
+ }
2471
+ }
2472
+
2473
+ obj.putSFSArray('value', listItems);
2474
+ }
2475
+
2476
+ return obj;
2477
+ }
2478
+
2479
+ /**
2480
+ * Return a description of the ConfigurationParameter instance.
2481
+ */
2482
+ toString()
2483
+ {
2484
+ let s = ``;
2485
+ s += `Configuration parameter: ${this.name}\n`;
2486
+ s += `\ttype: ${this.type}\n`;
2487
+ s += `\tlabel: ${this.label}\n`;
2488
+ s += `\tcategory name: ${this.category}\n`;
2489
+ s += `\tcategory id: ${this.categoryId}\n`;
2490
+ s += `\ttooltip: ${this.tooltip}\n`;
2491
+ s += `\tvalue: ${this.value}\n`;
2492
+ s += `\ttrigger: ${this.trigger}\n`;
2493
+ s += `\ttrigger data: ${this.triggerData}\n`;
2494
+ s += `\tclient only: ${this.clientOnly}\n`;
2495
+ s += `\tvalidator: ${this.validator}\n`;
2496
+ s += `\tis modified: ${this.isModified}\n`;
2497
+
2498
+ if (this.attributes != null)
2499
+ {
2500
+ s += `\tcomponent attributes:\n`;
2501
+
2502
+ for (let s1 in this.attributes)
2503
+ s += `\t\t${s1} --> ${this.attributes[s1]}\n`;
2504
+ }
2505
+
2506
+ if (this.dataProvider != null)
2507
+ s += `\tdata provider: ${this.dataProvider}\n`;
2508
+
2509
+ if (this.separator != null)
2510
+ {
2511
+ s += `\tseparator:\n`;
2512
+
2513
+ for (let s2 in this.separator)
2514
+ s += `\t\t${s2} --> ${this.separator[s2]}\n`;
2515
+ }
2516
+
2517
+ if (this._listItems != null && this._listItems.length > 0)
2518
+ {
2519
+ s += `\t# list items: ${this._listItems.length}\n`;
2520
+
2521
+ for (let i = 0; i < this._listItems.length; i++)
2522
+ {
2523
+ s += `\tlist item ${i} sub-parameters:\n`;
2524
+ for (let e = 0; e < this._listItems[i].length; e++)
2525
+ s += `\t\t${this._listItems[i][e].toCompactString()}\n`;
2526
+ }
2527
+
2528
+ s += `\tclass name: ${this.clazz}\n`;
2529
+ }
2530
+
2531
+ return s;
2532
+ }
2533
+
2534
+ /**
2535
+ * Return a compact description of the ConfigurationParameter instance.
2536
+ */
2537
+ toCompactString()
2538
+ {
2539
+ return `Configuration parameter '${this.name}': ${this.value} ${this.isModified ? '[X]' : '[ ]'}`;
2540
+ }
2541
+
2542
+ //---------------------------------------------
2543
+ // PRIVATE METHODS
2544
+ //---------------------------------------------
2545
+
2546
+ /**
2547
+ * Retrieve the category id form the category name.
2548
+ * Spaces and invalid characters are removed; words are separated using capitals.
2549
+ */
2550
+ _setIdFromCategoryName(categoryName)
2551
+ {
2552
+ this._categoryId = categoryName;
2553
+
2554
+ // Strip invalid characters
2555
+ var pattern = /[^0-9a-zA-Z]/g;
2556
+ this._categoryId = this._categoryId.replace(pattern, ' ');
2557
+
2558
+ // Capitalize words
2559
+ var words = this._categoryId.split(' ');
2560
+ this._categoryId = '';
2561
+
2562
+ for (let i = 0; i < words.length; i++)
2563
+ {
2564
+ let word = words[i];
2565
+ if (word.length > 0)
2566
+ this._categoryId += (i > 0 ? word.substr(0,1).toUpperCase() : word.substr(0,1).toLowerCase()) + (word.length > 1 ? word.substr(1) : "");
2567
+ }
2568
+
2569
+ if (this._categoryId.length == 0)
2570
+ this._categoryId = this.DEFAULT_CATEGORY_ID;
2571
+ }
2572
+
2573
+ _setSubConfigurationParams(_listValues)
2574
+ {
2575
+ this._listItems = [];
2576
+
2577
+ for (let obj of _listValues)
2578
+ {
2579
+ let listItem = [];
2580
+
2581
+ for (let defaultCP of this.defaultListItem)
2582
+ {
2583
+ let subCP = defaultCP.clone(false);
2584
+ subCP.value = obj[subCP.name];
2585
+
2586
+ listItem.push(subCP);
2587
+ }
2588
+
2589
+ this._listItems.push(listItem);
2590
+ }
2591
+ }
2592
+
2593
+ _getSubConfigurationParamsValues()
2594
+ {
2595
+ let _listValues = [];
2596
+
2597
+ for (let listItem of this._listItems)
2598
+ {
2599
+ let obj = {};
2600
+
2601
+ for (let subCP of listItem)
2602
+ {
2603
+ if (subCP.value != null)
2604
+ obj[subCP.name] = subCP.value;
2605
+ }
2606
+
2607
+ _listValues.push(obj);
2608
+ }
2609
+
2610
+ return _listValues;
2611
+ }
2612
+ }
2613
+
2614
+
2615
+ /***/ })
2616
+
2617
+ }]);
2618
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXRzL2pzL2NvcmUvbW9kdWxlcy9tb2R1bGUtMTJ+bW9kdWxlLTEzfm1vZHVsZS05LmJ1bmRsZS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1jaGVjay1ib3guanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWRyb3AtZG93bi1saXN0LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1kdWFsLWxpc3QuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWZvcm0taXRlbS5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctZ3JpZC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctbGFiZWwuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLW51bWVyaWMtc3RlcHBlci5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctdGV4dC1pbnB1dC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci9jb25maWctdmVjdG9yLTNkLmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL2NvbXBvbmVudHMvdWlidWlsZGVyL3dpZGdldHMvbGlzdC1pdGVtLWVkaXRvci5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy9jb21wb25lbnRzL3VpYnVpbGRlci93aWRnZXRzL3ZlY3Rvci0zZC1pbnB1dC5qcyIsIndlYnBhY2s6Ly9hcHBsaWNhdGlvbi8uL3NyYy91dGlscy91aWJ1aWxkZXIvY29uZmlnLWZvcm0taXRlbS1mYWN0b3J5LmpzIiwid2VicGFjazovL2FwcGxpY2F0aW9uLy4vc3JjL3V0aWxzL3VpYnVpbGRlci9jb25maWctaW50ZXJmYWNlLWJ1aWxkZXIuanMiLCJ3ZWJwYWNrOi8vYXBwbGljYXRpb24vLi9zcmMvdXRpbHMvdWlidWlsZGVyL2NvbmZpZ3VyYXRpb24tcGFyYW1ldGVyLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Q29uZmlnRm9ybUl0ZW19IGZyb20gJy4vY29uZmlnLWZvcm0taXRlbSc7XG5pbXBvcnQge0NvbmZpZ0xhYmVsfSBmcm9tICcuL2NvbmZpZy1sYWJlbCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdDaGVja0JveCBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIGEgc2ltcGxlIGxhYmVsIGlzIHVzZWQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0XHRsZXQgY29uZmlnID0ge1xuXHRcdFx0XHR0eXBlOiAnY2hlY2tib3gnLFxuXHRcdFx0XHRjbGFzczogJycsXG5cdFx0XHRcdGlkOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdG5hbWU6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdFx0J2RhdGEtcm9sZSc6ICdzd2l0Y2gnLFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0QXR0cmlidXRlcyhjb25maWcpO1xuXG5cdFx0XHQvLyBTZXQgYWRkaXRpb25hbCB3aWRnZXQgYXR0cmlidXRlcyBiYXNlZCBvbiB2YWxpZGF0aW9uIHJ1bGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gQ3JlYXRlIHdpZGdldCdzIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSAkKCc8aW5wdXQ+JywgY29uZmlnKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBDb25maWdMYWJlbCgpO1xuXG5cdFx0Ly8gUmV0dXJuIGNvbXBvbmVudFxuXHRcdHJldHVybiB0aGlzLl93aWRnZXRIdG1sO1xuXHR9XG5cblx0LyoqXG5cdCAqIEluaXRpYWxpemUgd2lkZ2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG4gICBfaW5pdGlhbGl6ZSgpXG4gICB7XG5cdCAgIGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHQgICB7XG5cdFx0ICAgLy8gSW5pdGlhbGl6ZSBrZW5kbyB3aWRnZXRcblx0XHQgICBrZW5kby5pbml0KHRoaXMuX3dpZGdldEh0bWwpO1xuXG5cdFx0ICAgLy8gU2F2ZSByZWYuIHRvIHdpZGdldFxuXHRcdCAgIHRoaXMuX2lubmVyV2lkZ2V0ID0gdGhpcy5fd2lkZ2V0SHRtbC5kYXRhKCdrZW5kb1N3aXRjaCcpO1xuXG5cdFx0ICAgLy8gRW5hYmxlIHZhbHVlIGNvbW1pdCBiaW5kaW5nXG5cdFx0ICAgdGhpcy5faW5uZXJXaWRnZXQuYmluZCgnY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0ICAgfVxuXG5cdCAgIC8vIFByb2NlZWQgd2l0aCBpbml0aWFsaXphdGlvblxuXHQgICBzdXBlci5faW5pdGlhbGl6ZSgpO1xuICAgfVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIHRoZSBsYWJlbCB0ZXh0IGlzIHNldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC52YWx1ZSh0aGlzLl9kYXRhLnZhbHVlKTtcblx0XHRlbHNlXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLnZhbHVlID0gdGhpcy5fZGF0YS52YWx1ZTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgZGlzYWJsZWQgc3RhdGUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldEVkaXRFbmFibGVkKClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdFx0dGhpcy5faW5uZXJXaWRnZXQuZW5hYmxlKHRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl9pbm5lcldpZGdldC52YWx1ZSgpO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnY29uZmlnLWNoZWNrLWJveCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctY2hlY2stYm94JywgQ29uZmlnQ2hlY2tCb3gpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0Ryb3BEb3duTGlzdCBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIGEgc2ltcGxlIGxhYmVsIGlzIHVzZWQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0XHRsZXQgY29uZmlnID0ge1xuXHRcdFx0XHRjbGFzczogJ2Zvcm0tY29udHJvbCcsXG5cdFx0XHRcdGlkOiB0aGlzLl9kYXRhLm5hbWUsXG5cdFx0XHRcdG5hbWU6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdFx0J2RhdGEtcm9sZSc6ICdkcm9wZG93bmxpc3QnLFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0QXR0cmlidXRlcyhjb25maWcpO1xuXG5cdFx0XHQvLyBTZXQgYWRkaXRpb25hbCB3aWRnZXQgYXR0cmlidXRlcyBiYXNlZCBvbiB2YWxpZGF0aW9uIHJ1bGVzIChzZWUgcGFyZW50IGNsYXNzKVxuXHRcdFx0dGhpcy5fc2V0V2lkZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gQ3JlYXRlIHdpZGdldCdzIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSAkKCc8aW5wdXQ+JywgY29uZmlnKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBDb25maWdMYWJlbCgpO1xuXG5cdFx0Ly8gUmV0dXJuIGNvbXBvbmVudFxuXHRcdHJldHVybiB0aGlzLl93aWRnZXRIdG1sO1xuXHR9XG5cblx0LyoqXG5cdCAqIEluaXRpYWxpemUgd2lkZ2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG4gICBfaW5pdGlhbGl6ZSgpXG4gICB7XG5cdCAgIGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHQgICB7XG5cdFx0ICAgLy8gSW5pdGlhbGl6ZSBrZW5kbyB3aWRnZXRcblx0XHQgICBrZW5kby5pbml0KHRoaXMuX3dpZGdldEh0bWwpO1xuXG5cdFx0ICAgLy8gU2F2ZSByZWYuIHRvIHdpZGdldFxuXHRcdCAgIHRoaXMuX2lubmVyV2lkZ2V0ID0gdGhpcy5fd2lkZ2V0SHRtbC5kYXRhKCdrZW5kb0Ryb3BEb3duTGlzdCcpO1xuXG5cdFx0ICAgLy8gU2V0IGxpc3QgaXRlbXNcblx0XHQgICB0aGlzLl9pbm5lcldpZGdldC5zZXREYXRhU291cmNlKHRoaXMuX2dldERhdGFTb3VyY2UodGhpcy5fZGF0YS5kYXRhUHJvdmlkZXIpKVxuXG5cdFx0ICAgLy8gRW5hYmxlIHZhbHVlIGNvbW1pdCBiaW5kaW5nXG5cdFx0ICAgdGhpcy5fd2lkZ2V0SHRtbC5iaW5kKCdjaGFuZ2UnLCAkLnByb3h5KHRoaXMuX29uVmFsdWVJbnB1dCwgdGhpcykpO1xuXHQgICB9XG5cblx0ICAgLy8gUHJvY2VlZCB3aXRoIGluaXRpYWxpemF0aW9uXG5cdCAgIHN1cGVyLl9pbml0aWFsaXplKCk7XG4gICB9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgdGhlIGxhYmVsIHRleHQgaXMgc2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRWYWx1ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX2lubmVyV2lkZ2V0LnZhbHVlKHRoaXMuX2RhdGEudmFsdWUpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsdWUgPSB0aGlzLl9kYXRhLnZhbHVlO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC53cmFwcGVyLmF0dHIoJ2Rpc2FibGVkJywgIXRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl9pbm5lcldpZGdldC52YWx1ZSgpO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0X2dldERhdGFTb3VyY2UoZHBTdHJpbmcpXG5cdHtcblx0XHRpZiAoZHBTdHJpbmcpXG5cdFx0XHRyZXR1cm4gZHBTdHJpbmcuc3BsaXQoJywnKTtcblxuXHRcdC8vIEluIGNhc2UgdGhlIGRhdGFwcm92aWRlciBpcyBlbXB0eSwgYWRkIGF0IGxlYXN0IHRoZSBjdXJyZW50IHZhbHVlXG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIFt0aGlzLl9kYXRhLnZhbHVlXTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1kcm9wLWRvd24tbGlzdCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctZHJvcC1kb3duLWxpc3QnLCBDb25maWdEcm9wRG93bkxpc3QpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcblxuZXhwb3J0IGNsYXNzIENvbmZpZ0R1YWxMaXN0IGV4dGVuZHMgQ29uZmlnRm9ybUl0ZW1cbntcblx0Y29uc3RydWN0b3IoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZylcblx0e1xuXHQgICAgc3VwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlIHdpZGdldCB0byByZW5kZXIgdGhlIENvbmZpZ1BhcmFtZXRlci5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGRpdj4nKTtcblxuXHRcdGNvbnN0IGF2YWlsYWJsZUlkID0gdGhpcy5fZ2V0SWQodGhpcy5fZGF0YS5uYW1lLCAnYXZhaWxhYmxlJyk7XG5cdFx0Y29uc3Qgc2VsZWN0ZWRJZCA9IHRoaXMuX2dldElkKHRoaXMuX2RhdGEubmFtZSwgJ3NlbGVjdGVkJyk7XG5cblx0XHQvLyBDcmVhdGUgaGVhZGVyIGZvciBsYWJlbHNcblx0XHRsZXQgaGVhZGVyID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICdmb3JtLWxhYmVsLWNvbnRhaW5lciBkdWFsLWxpc3QtbGFiZWxzJ30pO1xuXG5cdFx0aGVhZGVyLmFwcGVuZCgkKCc8bGFiZWw+Jywge1xuXHRcdFx0Y2xhc3M6ICdmb250LWl0YWxpYyBmb3JtLWxhYmVsIGR1YWwtbGlzdC1sZWZ0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHRcdGZvcjogYXZhaWxhYmxlSWQsXG5cdFx0fSkudGV4dCgnQXZhaWxhYmxlJykpO1xuXG5cdFx0aGVhZGVyLmFwcGVuZCgkKCc8bGFiZWw+Jywge1xuXHRcdFx0Y2xhc3M6ICdmb250LWl0YWxpYyBmb250LXdlaWdodC1ib2xkIGZvcm0tbGFiZWwgZHVhbC1saXN0LXJpZ2h0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHRcdGZvcjogc2VsZWN0ZWRJZCxcblx0XHR9KS50ZXh0KCdTZWxlY3RlZCcpKTtcblxuXHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKGhlYWRlcik7XG5cblx0XHQvLyBBZGQgYXZhaWxhYmxlIGl0ZW1zIGxpc3Rcblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0SHRtbCA9ICQoJzxzZWxlY3Q+Jywge1xuXHRcdFx0aWQ6IGF2YWlsYWJsZUlkLFxuXHRcdFx0Y2xhc3M6ICdkdWFsLWxpc3QtbGVmdC1jb2wnICsgKCF0aGlzLl9kYXRhLmVkaXRhYmxlID8gJyBuby1pbnRlcmFjdCcgOiAnJyksXG5cdFx0fSk7XG5cdFx0dGhpcy5fd2lkZ2V0SHRtbC5hcHBlbmQodGhpcy5fYXZhaWxhYmxlTGlzdEh0bWwpO1xuXG5cdFx0Ly8gQWRkIHNlbGVjdGVkIGl0ZW1zIGxpc3Rcblx0XHR0aGlzLl9zZWxlY3RlZExpc3RIdG1sID0gJCgnPHNlbGVjdD4nLCB7XG5cdFx0XHRpZDogc2VsZWN0ZWRJZCxcblx0XHRcdGNsYXNzOiAnZHVhbC1saXN0LXJpZ2h0LWNvbCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKSxcblx0XHR9KTtcblx0XHR0aGlzLl93aWRnZXRIdG1sLmFwcGVuZCh0aGlzLl9zZWxlY3RlZExpc3RIdG1sKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8vIElEcyBjb250YWluaW5nIGEgXCIuXCIgY2F1c2UgaXNzdWVzIHRvIGNvbm5lY3RlZCBsaXN0c1xuXHRfZ2V0SWQobmFtZSwgc3VmZml4KVxuXHR7XG5cdFx0cmV0dXJuIG5hbWUucmVwbGFjZSgnLicsICdfJykgKyAnLScgKyBzdWZmaXg7XG5cdH1cblxuXHQvKipcblx0ICogSW5pdGlhbGl6ZSB3aWRnZXQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2luaXRpYWxpemUoKVxuXHR7XG5cdFx0Ly8gSW5pdGlhbGl6ZSBcImF2YWxhYmxlXCIgbGlzdGJveFxuXHRcdHRoaXMuX2F2YWlsYWJsZUxpc3QgPSB0aGlzLl9hdmFpbGFibGVMaXN0SHRtbC5rZW5kb0xpc3RCb3goe1xuICAgICAgICAgICAgY29ubmVjdFdpdGg6IHRoaXMuX2dldElkKHRoaXMuX2RhdGEubmFtZSwgJ3NlbGVjdGVkJyksXG4gICAgICAgICAgICB0b29sYmFyOiB7XG4gICAgICAgICAgICAgICAgdG9vbHM6IHRoaXMuX2RhdGEuZWRpdGFibGUgPyBbJ3RyYW5zZmVyVG8nLCAndHJhbnNmZXJGcm9tJywgJ3RyYW5zZmVyQWxsVG8nLCAndHJhbnNmZXJBbGxGcm9tJ10gOiBbXVxuICAgICAgICAgICAgfSxcblx0XHRcdHRlbXBsYXRlOiBcIjxkaXY+Izp2YWx1ZSM8L2Rpdj5cIixcblx0XHRcdHNlbGVjdGFibGU6ICdtdWx0aXBsZScsXG4gICAgICAgIH0pLmRhdGEoJ2tlbmRvTGlzdEJveCcpO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBcInNlbGVjdGVkXCIgbGlzdGJveFxuICAgICAgICB0aGlzLl9zZWxlY3RlZExpc3QgPSB0aGlzLl9zZWxlY3RlZExpc3RIdG1sLmtlbmRvTGlzdEJveCh7XG5cdFx0XHR0ZW1wbGF0ZTogXCI8ZGl2PiM6dmFsdWUjPC9kaXY+XCIsXG5cdFx0XHRzZWxlY3RhYmxlOiAnbXVsdGlwbGUnLFxuXHRcdFx0Ly8gVGhlIGZvbGxvd2luZyBsaXN0ZW5lcnMgY2FuJ3QgYmUgdXNlZCBiZWNhdXNlIGV2ZW50cyBhcmUgZmlyZWQgYmVmb3JlIHRoZSBkYXRhc291cmNlIGlzIGFjdHVhbGx5IHVwZGF0ZWRcblx0XHRcdC8vIFdlIGhhdmUgdG8gdXNlIGEgY2hhbmdlIGV2ZW50IGxpc3RlbmVyIG9uIHRoZSBkYXRhc291cmNlIChzZWUgYmVsb3cpLCBldmVuIGlmIG5vdCBvcHRpbWFsXG5cdFx0XHQvL2FkZDogJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpLFxuXHRcdFx0Ly9yZW1vdmU6ICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKSxcblx0XHR9KS5kYXRhKCdrZW5kb0xpc3RCb3gnKTtcblxuXHRcdC8vIFByb2NlZWQgd2l0aCBpbml0aWFsaXphdGlvblxuXHRcdHN1cGVyLl9pbml0aWFsaXplKCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRhdGFzb3VyY2UuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldFZhbHVlKClcblx0e1xuXHRcdGxldCBhdmFpbGFibGVBcnIgPSB0aGlzLl9kYXRhLmRhdGFQcm92aWRlciAhPSAnJyA/IHRoaXMuX2RhdGEuZGF0YVByb3ZpZGVyLnNwbGl0KCcsJykgOiBbXTtcblx0XHRsZXQgc2VsZWN0ZWRBcnIgPSB0aGlzLl9kYXRhLnZhbHVlICE9ICcnID8gdGhpcy5fZGF0YS52YWx1ZS5zcGxpdCgnLCcpIDogW107XG5cblx0XHQvLyBSZW1vdmUgc2VsZWN0ZWQgdmFsdWVzIGZyb20gYXZhaWxhYmxlIHZhbHVlc1xuXHRcdGlmIChzZWxlY3RlZEFyci5sZW5ndGggPiAwKVxuXHRcdHtcblx0XHRcdGxldCB0ZW1wID0gW107XG5cblx0XHRcdGZvciAobGV0IHZhbCBvZiBhdmFpbGFibGVBcnIpXG5cdFx0XHR7XG5cdFx0XHRcdGlmIChzZWxlY3RlZEFyci5pbmRleE9mKHZhbCkgPT0gLTEpXG5cdFx0XHRcdFx0dGVtcC5wdXNoKHZhbCk7XG5cdFx0XHR9XG5cblx0XHRcdGF2YWlsYWJsZUFyciA9IHRlbXA7XG5cdFx0fVxuXG5cdFx0Ly8gQ29udmVydCBsaXN0cyBvZiBzdHJpbmdzIHRvIGxpc3RzIG9mIG9iamVjdHNcblx0XHRsZXQgYXZhaWxhYmxlVmFsdWVzID0gW107XG5cdFx0Zm9yIChsZXQgdmFsIG9mIGF2YWlsYWJsZUFycilcblx0XHRcdGF2YWlsYWJsZVZhbHVlcy5wdXNoKHt2YWx1ZTogdmFsfSk7XG5cblx0XHRsZXQgc2VsZWN0ZWRWYWx1ZXMgPSBbXTtcblx0XHRmb3IgKGxldCB2YWwgb2Ygc2VsZWN0ZWRBcnIpXG5cdFx0XHRzZWxlY3RlZFZhbHVlcy5wdXNoKHt2YWx1ZTogdmFsfSk7XG5cblx0XHQvLyBDbGVhciBzZWxlY3Rpb25cblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cdFx0dGhpcy5fc2VsZWN0ZWRMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cblx0XHQvLyBTZXQgZGF0YXNvdXJjZXNcblx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LnNldERhdGFTb3VyY2UobmV3IGtlbmRvLmRhdGEuRGF0YVNvdXJjZSh7XG5cdFx0XHRkYXRhOiBhdmFpbGFibGVWYWx1ZXNcblx0XHR9KSk7XG5cblx0XHR0aGlzLl9zZWxlY3RlZExpc3Quc2V0RGF0YVNvdXJjZShuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKHtcblx0XHRcdGRhdGE6IHNlbGVjdGVkVmFsdWVzLFxuXHRcdFx0Ly8gV2UgbGlzdGVuIHRvIHRoZSBjaGFuZ2UgZXZlbnQgaW5zdGVhZCBvZiB0aGUgYWRkL3JlbW92ZSBldmVudHMgb24gdGhlIGxpc3Rib3gsIGJlY2F1c2UgdGhvc2UgYXJlIGZpcmVkIGJlZm9yZSB0aGUgZGF0YXNvdXJjZSBpcyB1cGRhdGVkXG5cdFx0XHQvLyBUaGlzIGlzIG5vdCBvcHRpbWFsIGJlY2F1c2UgdGhlIGV2ZW50IGlzIGZpcmVkIGZvciBlYWNoIGl0ZW0gYWRkZWQgdG8gb3IgcmVtb3ZlZCBmcm9tIHRoZSBkYXRhc291cmNlXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKVxuXHRcdH0pKTtcblxuXHRcdC8vIERpc2FibGUgZWRpdGluZ1xuXHRcdGlmICghdGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmVuYWJsZSgnLmstaXRlbScsIGZhbHNlKTtcblx0XHRcdHRoaXMuX3NlbGVjdGVkTGlzdC5lbmFibGUoJy5rLWl0ZW0nLCBmYWxzZSk7XG5cdFx0fVxuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gQ2xlYXIgc2VsZWN0aW9uXG5cdFx0XHR0aGlzLl9hdmFpbGFibGVMaXN0LmNsZWFyU2VsZWN0aW9uKCk7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZExpc3QuY2xlYXJTZWxlY3Rpb24oKTtcblxuXHRcdFx0Ly8gRW5hYmxlL2Rpc2FibGUgbGlzdHNcblx0XHRcdHRoaXMuX2F2YWlsYWJsZUxpc3Qud3JhcHBlci5hdHRyKCdkaXNhYmxlZCcsICF0aGlzLl9lZGl0RW5hYmxlZCk7XG5cdFx0XHR0aGlzLl9zZWxlY3RlZExpc3Qud3JhcHBlci5hdHRyKCdkaXNhYmxlZCcsICF0aGlzLl9lZGl0RW5hYmxlZCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB2YWx1ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfb25WYWx1ZUlucHV0KGUpXG5cdHtcblx0XHRsZXQgbGlzdERhdGEgPSB0aGlzLl9zZWxlY3RlZExpc3QuZGF0YVNvdXJjZS5kYXRhKCk7XG5cblx0XHQvLyBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdG8gbmV3IHZhbHVlXG5cdFx0dGhpcy5fZGF0YS52YWx1ZSA9IGxpc3REYXRhLm1hcChlID0+IGUudmFsdWUpLmpvaW4oJywnKTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1kdWFsLWxpc3QnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLWR1YWwtbGlzdCcsIENvbmZpZ0R1YWxMaXN0KTtcbiIsImV4cG9ydCBjbGFzcyBDb25maWdGb3JtSXRlbSBleHRlbmRzIEhUTUxFbGVtZW50XG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKCk7XG5cblx0XHR0aGlzLmlkID0gJ2Zvcm0taXRlbS0nICsgY29uZmlnUGFyYW0ubmFtZTtcblx0XHR0aGlzLl9lZGl0RW5hYmxlZCA9IGVkaXRFbmFibGVkO1xuXHRcdHRoaXMuX2RhdGEgPSBjb25maWdQYXJhbTtcblxuXHRcdC8vIENyZWF0ZSBmb3JtIGl0ZW0gdmlld1xuXHRcdHRoaXMuX2J1aWxkVmlldyhpbkRpYWxvZyk7XG5cblx0XHQvLyBJbml0aWFsaXplIGZvcm0gaXRlbVxuXHRcdHRoaXMuX2luaXRpYWxpemUoKTtcblx0fVxuXG5cdGNvbm5lY3RlZENhbGxiYWNrKClcblx0e1xuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHQvLyBOT1RFOiB3aGVuIGEgQ29uZmlnRm9ybUl0ZW0gaXMgaW5zdGFudGlhdGVkLCB0aGUgX3RyaWdnZXJFdmVudCBtZXRob2QgaXMgY2FsbGVkIGFzIHNvb24gYXMgaXRzIHZhbHVlIGlzIHNldC5cblx0XHQvLyBXaGVuIHRoaXMgaGFwcGVuc28sIGR1ZSB0byB0aGUgZmFjdCB0aGF0IHRoZSBvYmplY3QgaXMgbm90IHlldCBpbiB0aGUgRE9NLCB0aGUgZXZlbnQgaXMgbm90IGNhdGNoZWQgYnkgdGhlIGxpc3RlbmVyXG5cdFx0Ly8gKHdoaWNoIGlzIGF0dGFjaGVkIHRvIHRoZSBvdXRlciBjb250YWluZXIpLiBTbyBmb3JjaW5nIHRoZSBldmVudCB0byB0cmlnZ2VyIGFnYWluIGFzIHNvb24gYXMgdGhlIENvbmZpZ0Zvcm1JdGVtXG5cdFx0Ly8gaXMgYXBwZW5kZWQgdG8gdGhlIERPTSBpcyBuZWVkZWQuXG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cblxuXHRzZXQgZGF0YShjb25maWdQYXJhbSlcblx0e1xuXHRcdHRoaXMuX2RhdGEgPSBjb25maWdQYXJhbTtcblx0XHR0aGlzLl9zZXRXaWRnZXRWYWx1ZSgpO1xuXHR9XG5cblx0Z2V0IGRhdGEoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2RhdGE7XG5cdH1cblxuXHRzZXQgZWRpdEVuYWJsZWQoZW5hYmxlKVxuXHR7XG5cdFx0aWYgKGVuYWJsZSAhPSB0aGlzLl9lZGl0RW5hYmxlZClcblx0XHR7XG5cdFx0XHR0aGlzLl9lZGl0RW5hYmxlZCA9IGVuYWJsZTtcblx0XHRcdHRoaXMuX3NldFdpZGdldEVkaXRFbmFibGVkKCk7XG5cdFx0fVxuXHR9XG5cblx0Z2V0IGVkaXRFbmFibGVkKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9lZGl0RW5hYmxlZDtcblx0fVxuXG5cdF9idWlsZFZpZXcoaXNJbnNpZGVEaWFsb2cpXG5cdHtcblx0XHRpZiAoIWlzSW5zaWRlRGlhbG9nKVxuXHRcdHtcblx0XHRcdC8vIFNldCBhZGRpdGlvbmFsIGNsYXNzZXMgZm9yIGlubmVyIHdpZGdldFxuXHRcdFx0bGV0IGNsYXNzTmFtZXMgPSAnJztcblxuXHRcdFx0c3dpdGNoICh0aGlzLl9kYXRhLnR5cGUpXG5cdFx0XHR7XG5cdFx0XHRcdGNhc2UgJ0R1YWxMaXN0Jzpcblx0XHRcdFx0XHRjbGFzc05hbWVzID0gJ2NvbC1zbS03IGNvbC1sZy04Jztcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAnRGF0YUdyaWQnOlxuXHRcdFx0XHRcdGNsYXNzTmFtZXMgPSAnY29sLXNtJzsgLy8gVXNlICdjb2wtc20tNyBjb2wtbGctOCcgZm9yIERhdGFHcmlkIHRvbz9cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRjbGFzc05hbWVzID0gJ2NvbC1zbS1hdXRvJztcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBHZW5lcmF0ZSBib2lsZXJwbGF0ZSBodG1sLCBzdXJyb3VuZGluZyB0aGUgYWN0dWFsIHdpZGdldCAobGFiZWwsIG51bWVyaWMgc3RlcHBlciwgZXRjKVxuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSBgXG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwIHBvc2l0aW9uLXJlbGF0aXZlIHJvd1wiPlxuXHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJjb2wtc20tNSBjb2wtbGctNCBjb2wtZm9ybS1sYWJlbCBmb3JtLWxhYmVsLWNvbnRhaW5lclwiPlxuXHRcdFx0XHRcdFx0PGxhYmVsIGZvcj1cIiR7dGhpcy5fZGF0YS5uYW1lfVwiIGNsYXNzPVwiZm9ybS1sYWJlbCAkeyh0aGlzLl9kYXRhLmNsaWVudE9ubHkgPyAnY2xpZW50LW9ubHknIDogJycpfVwiPiR7dGhpcy5fZGF0YS5sYWJlbH0gPGkgY2xhc3M9XCJmYXMgZmEtcXVlc3Rpb24tY2lyY2xlIHRleHQtbXV0ZWQgaGVscFwiIHRpdGxlPVwiJHt0aGlzLl9kYXRhLnRvb2x0aXB9XCI+PC9pPjwvbGFiZWw+XG5cdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cImlubmVyLXdpZGdldCBhbGlnbi1zZWxmLWNlbnRlciAke2NsYXNzTmFtZXN9XCI+XG5cdFx0XHRcdFx0XHQ8c3BhbiBjbGFzcz1cImstaW52YWxpZC1tc2dcIiBkYXRhLWZvcj1cIiR7dGhpcy5fZGF0YS5uYW1lfVwiPjwvc3Bhbj5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PC9kaXY+XG5cdFx0XHRgO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSBgXG5cdFx0XHRcdDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwIHBvc2l0aW9uLXJlbGF0aXZlXCI+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cImNvbC1mb3JtLWxhYmVsIGZvcm0tbGFiZWwtY29udGFpbmVyXCI+XG5cdFx0XHRcdFx0XHQ8bGFiZWwgZm9yPVwiJHt0aGlzLl9kYXRhLm5hbWV9XCIgY2xhc3M9XCJmb3JtLWxhYmVsICR7KHRoaXMuX2RhdGEuY2xpZW50T25seSA/ICdjbGllbnQtb25seScgOiAnJyl9XCI+JHt0aGlzLl9kYXRhLmxhYmVsfSA8aSBjbGFzcz1cImZhcyBmYS1xdWVzdGlvbi1jaXJjbGUgdGV4dC1tdXRlZCBoZWxwXCIgdGl0bGU9XCIke3RoaXMuX2RhdGEudG9vbHRpcH1cIj48L2k+PC9sYWJlbD5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHQ8ZGl2IGNsYXNzPVwiaW5uZXItd2lkZ2V0XCI+XG5cdFx0XHRcdFx0XHQ8c3BhbiBjbGFzcz1cImstaW52YWxpZC1tc2dcIiBkYXRhLWZvcj1cIiR7dGhpcy5fZGF0YS5uYW1lfVwiPjwvc3Bhbj5cblx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0PC9kaXY+XG5cdFx0XHRgO1xuXHRcdH1cblxuXHRcdC8vIENyZWF0ZSBpbm5lciB3aWRnZXQgKG11c3QgYmUgb3ZlcnJpZGRlbilcblx0XHRsZXQgd2lkZ2V0ID0gdGhpcy5fZ2VuZXJhdGVJbm5lcldpZGdldCgpO1xuXG5cdFx0Ly8gQXBwZW5kIGlubmVyIHdpZGdldFxuXHRcdCQodGhpcykuZmluZCgnLmlubmVyLXdpZGdldCcpLnByZXBlbmQod2lkZ2V0KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBUTyBCRSBPVkVSUklEREVOXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHQvLyBTaG93IGFuIGVycm9yLCBzaG91bGQgYmUgb3ZlcnJpZGRlblxuXHRcdGNvbnNvbGUuZXJyb3IoYFVuYWJsZSB0byBjcmVhdGUgJHt0aGlzLl9kYXRhLnR5cGV9IGZvcm0gaXRlbSBmb3IgY29uZmlndXJhdGlvbiBwYXJhbWV0ZXIgJHt0aGlzLmlkfWApO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCBhdHRyaWJ1dGVzIG9uIHRoZSB3aWRnZXQgY29uZmlndXJhdGlvbiBvYmplY3QuXG5cdCAqL1xuXHRfc2V0V2lkZ2V0QXR0cmlidXRlcyhjb25maWcpXG5cdHtcblx0XHRjb25zdCBhdHRyaWJzID0gdGhpcy5fZGF0YS5hdHRyaWJ1dGVzO1xuXG5cdFx0aWYgKGF0dHJpYnMpXG5cdFx0e1xuXHRcdFx0Zm9yIChsZXQgYXR0ciBpbiBhdHRyaWJzKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25maWdbYXR0cl0gPSBhdHRyaWJzW2F0dHJdO1xuXG5cdFx0XHRcdGlmIChhdHRyID09ICdwYXR0ZXJuJylcblx0XHRcdFx0XHRjb25maWdbJ2RhdGEtcGF0dGVybi1tc2cnXSA9ICdDb250YWlucyBpbnZhbGlkIGNoYXJhY3RlcnMnO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgYWRkaXRpb25hbCBhdHRyaWJ1dGVzIG9uIHRoZSB3aWRnZXQgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gcHJvcGVybHkgdmFsaWRhdGUgaW5wdXQuXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsaWRhdGlvbkF0dHJpYnV0ZXMoY29uZmlnKVxuXHR7XG5cdFx0Y29uc3QgdmFsID0gdGhpcy5fZGF0YS52YWxpZGF0b3I7XG5cblx0XHRpZiAodmFsICE9IG51bGwgJiYgdmFsICE9ICcnKVxuXHRcdHtcblx0XHRcdGlmICh2YWwgPT0gJ2lwJylcblx0XHRcdHtcblx0XHRcdFx0Y29uZmlnWydwYXR0ZXJuJ10gPSAnXigyNVswLTVdfDJbMC00XVswLTldfFswMV0/WzAtOV1bMC05XT8pXFwuKDI1WzAtNV18MlswLTRdWzAtOV18WzAxXT9bMC05XVswLTldPylcXC4oMjVbMC01XXwyWzAtNF1bMC05XXxbMDFdP1swLTldWzAtOV0/KVxcLigyNVswLTVdfDJbMC00XVswLTldfFswMV0/WzAtOV1bMC05XT8pJCc7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1wYXR0ZXJuLW1zZyddID0gJ0ludmFsaWQgSVAgYWRkcmVzcyc7XG5cdFx0XHRcdGNvbmZpZ1sncmVxdWlyZWQnXSA9IHRydWU7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1yZXF1aXJlZC1tc2cnXSA9ICdSZXF1aXJlZCc7XG5cdFx0XHR9XG5cblx0XHRcdGVsc2UgaWYgKHZhbCA9PSAnbm90TnVsbCcpXG5cdFx0XHR7XG5cdFx0XHRcdGNvbmZpZ1sncmVxdWlyZWQnXSA9IHRydWU7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1yZXF1aXJlZC1tc2cnXSA9ICdSZXF1aXJlZCc7XG5cdFx0XHR9XG5cblx0XHRcdGVsc2UgaWYgKHZhbCA9PSAncHdkJylcblx0XHRcdHtcblx0XHRcdFx0Y29uZmlnWydwYXR0ZXJuJ10gPSAnXi57Nix9JCc7XG5cdFx0XHRcdGNvbmZpZ1snZGF0YS1wYXR0ZXJuLW1zZyddID0gJ01pbmltdW0gbGVuZ3RoOiA2IGNoYXJhY3RlcnMnO1xuXHRcdFx0fVxuXG5cdFx0XHRlbHNlIGlmICh2YWwgPT0gJ3Bvc051bScpXG5cdFx0XHR7XG5cdFx0XHRcdGNvbmZpZ1sncGF0dGVybiddID0gJ15bMC05XVxcZCokJztcblx0XHRcdFx0Y29uZmlnWydkYXRhLXBhdHRlcm4tbXNnJ10gPSAnTm9uLW5lZ2F0aXZlIG51bWJlciByZXF1aXJlZCc7XG5cdFx0XHR9XG5cblx0XHRcdGVsc2UgaWYgKHZhbCA9PSAnYW9pJylcblx0XHRcdHtcblx0XHRcdFx0Ly8gTm90aGluZyB0byBkb1xuXHRcdFx0XHQvLyBTZWUgS2VuZG8gdmFsaWRhdGlvbiBpbml0aWFsaXphdGlvbiBpbiBjb25maWctaW50ZXJmYWNlLWJ1aWxkZXIuanNcblx0XHRcdH1cblxuXHRcdFx0ZWxzZSBpZiAodmFsID09ICd1cmwnKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25maWdbJ3R5cGUnXSA9ICd1cmwnO1xuXHRcdFx0XHRjb25maWdbJ2RhdGEtdXJsLW1zZyddID0gJ0ludmFsaWQgVVJMJztcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogSW5pdGlhbGl6ZSBmb3JtIGl0ZW0uXG5cdCAqXG5cdCAqIE5PVEU6IG11c3QgYmUgb3ZlcnJpZGRlbiBpZiBpbm5lciB3aWRnZXQgcmVxdWlyZXMgc3BlY2lhbCBpbml0aWFsaXphdGlvbiAoZm9yIGV4YW1wbGUgS2VuZG8gd2lkZ2V0cylcblx0ICovXG5cdF9pbml0aWFsaXplKClcblx0e1xuXHRcdC8vIFNldCB2YWx1ZVxuIFx0ICAgdGhpcy5fc2V0V2lkZ2V0VmFsdWUoKTtcblxuIFx0ICAgLy8gU2V0IGVkaXQgZW5hYmxlZFxuIFx0ICAgdGhpcy5fc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBUTyBCRSBPVkVSUklEREVOXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0Ly8gTm90aGluZyB0byBkbywgbXVzdCBiZSBvdmVycmlkZGVuXG5cdH1cblxuXHQvKipcblx0ICogVE8gQkUgT1ZFUlJJRERFTlxuXHQgKi9cblx0X3NldFdpZGdldEVkaXRFbmFibGVkKClcblx0e1xuXHRcdC8vIE5vdGhpbmcgdG8gZG8sIG11c3QgYmUgb3ZlcnJpZGRlblxuXHR9XG5cblx0LyoqXG5cdCAqIFRPIEJFIE9WRVJSSURERU5cblx0ICovXG5cdF9vblZhbHVlSW5wdXQoZSlcblx0e1xuXHRcdC8vIE5vdGhpbmcgdG8gZG8sIG11c3QgYmUgb3ZlcnJpZGRlblxuXHR9XG5cblx0X3RyaWdnZXJFdmVudCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS50cmlnZ2VyKVxuXHRcdHtcblx0XHRcdGxldCBldmVudCA9IG5ldyBDdXN0b21FdmVudCgndmFsdWUtc2V0Jywge2RldGFpbDogbnVsbCwgYnViYmxlczogdHJ1ZSwgY2FuY2VsYWJsZTogdHJ1ZX0pO1xuXHRcdFx0dGhpcy5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcblx0XHR9XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdjb25maWctZm9ybS1pdGVtJykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2NvbmZpZy1mb3JtLWl0ZW0nLCBDb25maWdGb3JtSXRlbSk7XG4iLCJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuaW1wb3J0IHtMaXN0SXRlbUVkaXRvcn0gZnJvbSAnLi93aWRnZXRzL2xpc3QtaXRlbS1lZGl0b3InO1xuXG5leHBvcnQgY2xhc3MgQ29uZmlnR3JpZCBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0Ly8gQ3JlYXRlIG1haW4gd2lkZ2V0J3MgaHRtbFxuXHRcdHRoaXMuX3dpZGdldEh0bWwgPSAkKCc8ZGl2PicsIHtjbGFzczogJyd9KTtcblxuXHRcdC8vIFNldCBncmlkIHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0bGV0IGdyaWRDb25maWcgPSB7XG5cdFx0XHRpZDogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0bmFtZTogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0Y2xhc3M6ICdsaW1pdGVkLWhlaWdodCcgKyAoIXRoaXMuX2RhdGEuZWRpdGFibGUgPyAnIG5vLWludGVyYWN0JyA6ICcnKVxuXHRcdH07XG5cblx0XHQvLyBBcHBlbmQgZ3JpZCB0byBtYWluIGh0bWw7IGdyaWQgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gS2VuZG8gd2lkZ2V0IGR1cmluZyBpbml0aWFsaXphdGlvblxuXHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKCQoJzxkaXY+JywgZ3JpZENvbmZpZykpO1xuXG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gQlVUVE9OU1xuXG5cdFx0XHQvLyBDcmVhdGUgYnV0dG9ucyBjb250YWluZXJcblx0XHRcdGxldCBidXR0b25zID0gJCgnPGRpdj4nLCB7Y2xhc3M6ICdtdC0yIHRleHQtcmlnaHQnfSk7XG5cblx0XHRcdC8vIEFwcGVuZCBidXR0b25zIHRvIGNvbnRhaW5lclxuXHRcdFx0dGhpcy5fYWRkQnV0dG9uID0gJCgnPGJ1dHRvbj4nLCB7dHlwZTogJ2J1dHRvbicsIGNsYXNzOiAnay1idXR0b24gay1zZWNvbmRhcnknLCB0aXRsZTogJ0FkZCd9KS5hcHBlbmQoJCgnPGkgY2xhc3M9XCJmYXMgZmEtcGx1c1wiPjwvaT4nKSk7XG5cdFx0XHR0aGlzLl9lZGl0QnV0dG9uID0gJCgnPGJ1dHRvbj4nLCB7dHlwZTogJ2J1dHRvbicsIGNsYXNzOiAnay1idXR0b24gay1zZWNvbmRhcnkgbWwtMicsIHRpdGxlOiAnRWRpdCcsIGRpc2FibGVkOiB0cnVlfSkuYXBwZW5kKCQoJzxpIGNsYXNzPVwiZmFzIGZhLXBlblwiPjwvaT4nKSk7XG5cdFx0XHR0aGlzLl9yZW1vdmVCdXR0b24gPSAkKCc8YnV0dG9uPicsIHt0eXBlOiAnYnV0dG9uJywgY2xhc3M6ICdrLWJ1dHRvbiBrLXNlY29uZGFyeSBtbC0yJywgdGl0bGU6ICdSZW1vdmUnLCBkaXNhYmxlZDogdHJ1ZX0pLmFwcGVuZCgkKCc8aSBjbGFzcz1cImZhcyBmYS10aW1lc1wiPjwvaT4nKSk7XG5cblx0XHRcdGJ1dHRvbnMuYXBwZW5kKHRoaXMuX2FkZEJ1dHRvbik7XG5cdFx0XHRidXR0b25zLmFwcGVuZCh0aGlzLl9lZGl0QnV0dG9uKTtcblx0XHRcdGJ1dHRvbnMuYXBwZW5kKHRoaXMuX3JlbW92ZUJ1dHRvbik7XG5cblx0XHRcdC8vIEFwcGVuZCBidXR0b25zIGNvbnRhaW5lciB0byBtYWluIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKGJ1dHRvbnMpO1xuXG5cdFx0XHQvLyBDcmVhdGUgZWRpdCBkaWFsb2dcblx0XHRcdC8vIE5PVEU6IGRhdGEtZGlzbWlzcz1cIm1vZGFsXCIgb24gdGhlIGNsb3NlL2NhbmNlbCBidXR0b25zIHdhcyByZW1vdmVkIHRvIHdvcmsgYXJvdW5kIGFuIGlzc3VlIHdpdGggbmVzdGVkIG1vZGFscztcblx0XHRcdC8vIHRoZSBjdXN0b20gXCJkYXRhLWNhbmNlbFwiIGF0dHJpYnV0ZSBpcyB1c2VkIHRvIGFkZCBhIGN1c3RvbSBsaXN0ZW5lciB0byB0aGUgYnV0dG9uc1xuXHRcdFx0dGhpcy5fZWRpdERpYWxvZyA9ICQoYFxuXHRcdFx0XHQ8ZGl2IGNsYXNzPVwibW9kYWxcIiB0YWJpbmRleD1cIi0xXCIgcm9sZT1cImRpYWxvZ1wiIGFyaWEtbGFiZWxsZWRieT1cIm1vZGFsVGl0bGVcIiBhcmlhLWhpZGRlbj1cInRydWVcIiBkYXRhLWtleWJvYXJkPVwiZmFsc2VcIiBkYXRhLWJhY2tkcm9wPVwic3RhdGljXCI+XG5cdFx0XHRcdFx0PGRpdiBjbGFzcz1cIm1vZGFsLWRpYWxvZyBtb2RhbC1kaWFsb2ctY2VudGVyZWRcIiByb2xlPVwiZG9jdW1lbnRcIj5cblx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1jb250ZW50XCI+XG5cdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1oZWFkZXJcIj5cblx0XHRcdFx0XHRcdFx0XHQ8aDUgY2xhc3M9XCJtb2RhbC10aXRsZSB0ZXh0LXByaW1hcnlcIiBpZD1cIm1vZGFsVGl0bGVcIj4ke3RoaXMuX2RhdGEubGFiZWx9PC9oNT5cblx0XHRcdFx0XHRcdFx0XHQ8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImNsb3NlXCIgYXJpYS1sYWJlbD1cIkNsb3NlXCIgZGF0YS1jYW5jZWw9XCJtb2RhbFwiPlxuXHRcdFx0XHRcdFx0XHRcdFx0PHNwYW4gYXJpYS1oaWRkZW49XCJ0cnVlXCI+JnRpbWVzOzwvc3Bhbj5cblx0XHRcdFx0XHRcdFx0XHQ8L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0PC9kaXY+XG5cdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJtb2RhbC1ib2R5IGluLWZsb3ctaW52YWxpZC1tc2dcIj5cblxuXHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cIm1vZGFsLWZvb3RlciBmbGV4LWNvbHVtblwiPlxuXHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJkLWZsZXggdy0xMDBcIj5cblx0XHRcdFx0XHRcdFx0XHRcdDxkaXYgY2xhc3M9XCJmbGV4LWdyb3ctMSB0ZXh0LWxlZnRcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJrLWJ1dHRvbiBrLXByaW1hcnlcIj4uLi48L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdFx0PGRpdiBjbGFzcz1cImZsZXgtZ3Jvdy0xIHRleHQtcmlnaHRcIj5cblx0XHRcdFx0XHRcdFx0XHRcdFx0PGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJrLWJ1dHRvbiBrLXNlY29uZGFyeVwiIGRhdGEtY2FuY2VsPVwibW9kYWxcIj5DYW5jZWw8L2J1dHRvbj5cblx0XHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdFx0XHQ8L2Rpdj5cblx0XHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHRcdDwvZGl2PlxuXHRcdFx0XHQ8L2Rpdj5cblx0XHRcdGApO1xuXG5cdFx0XHQvLyBBZGQgbGlzdGVuZXIgdG8gZGlhbG9nIGhpZGUgZXZlbnRcblx0XHRcdHRoaXMuX2VkaXREaWFsb2cub24oJ2hpZGRlbi5icy5tb2RhbCcsICQucHJveHkodGhpcy5fb25FZGl0UGFuZWxIaWRkZW4sIHRoaXMpKTtcblxuXHRcdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIG1haW4gYnV0dG9uIGNsaWNrIGV2ZW50XG5cdFx0XHQkKCdidXR0b24uay1wcmltYXJ5JywgdGhpcy5fZWRpdERpYWxvZykub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vblN1Ym1pdEJ0Q2xpY2ssIHRoaXMpKTtcblxuXHRcdFx0Ly8gQWRkIGxpc3RlbmVyIHRvIGNsb3NlL2NhbmNlbCBidXR0b25zIGNsaWNrIGV2ZW50XG5cdFx0XHQkKCdidXR0b25bZGF0YS1jYW5jZWw9XCJtb2RhbFwiXScsIHRoaXMuX2VkaXREaWFsb2cpLm9uKCdjbGljaycsICQucHJveHkodGhpcy5fb25DYW5jZWxCdENsaWNrLCB0aGlzKSk7XG5cblx0XHRcdC8vIEFwcGVuZCBlZGl0IGRpYWxvZyB0byBtYWluIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwuYXBwZW5kKHRoaXMuX2VkaXREaWFsb2cpO1xuXHRcdH1cblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHdpZGdldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfaW5pdGlhbGl6ZSgpXG5cdHtcblx0XHRsZXQgY29sdW1ucyA9IFtdO1xuXHRcdGZvciAobGV0IHN1YkNvbmZpZ1BhcmFtIG9mIHRoaXMuX2RhdGEuZGVmYXVsdExpc3RJdGVtKVxuXHRcdHtcblx0XHRcdGxldCBjb2wgPSB7XG5cdFx0XHRcdGZpZWxkOiBzdWJDb25maWdQYXJhbS5uYW1lLFxuXHRcdFx0XHR0aXRsZTogc3ViQ29uZmlnUGFyYW0ubGFiZWwsXG5cdFx0XHRcdHdpZHRoOiAxMjBcblx0XHRcdH1cblxuXHRcdFx0Ly8gRGlzcGxheSBWIG9yIFggZm9yIGJvb2xlYW5zXG5cdFx0XHRpZiAodHlwZW9mIHN1YkNvbmZpZ1BhcmFtLnZhbHVlID09PSAnYm9vbGVhbicpXG5cdFx0XHRcdGNvbC50ZW1wbGF0ZSA9IGAjPSAke3N1YkNvbmZpZ1BhcmFtLm5hbWV9ID8gJzxpIGNsYXNzPVwiZmFzIGZhLWNoZWNrXCI+PC9pPicgOiAnPGkgY2xhc3M9XCJmYXMgZmEtdGltZXNcIj48L2k+JyAjYDtcblxuXHRcdFx0Ly8gSGlkZSBwYXNzd29yZHNcblx0XHRcdGlmIChzdWJDb25maWdQYXJhbS50eXBlID09ICdUZXh0SW5wdXQnICYmIHN1YkNvbmZpZ1BhcmFtLmF0dHJpYnV0ZXMgIT0gbnVsbCAmJiBzdWJDb25maWdQYXJhbS5hdHRyaWJ1dGVzLnR5cGUgPT0gJ3Bhc3N3b3JkJylcblx0XHRcdFx0Y29sLnRlbXBsYXRlID0gYCM9ICfigKInLnJlcGVhdChkYXRhLiR7c3ViQ29uZmlnUGFyYW0ubmFtZX0ubGVuZ3RoKSAjYDtcblxuXHRcdFx0Y29sdW1ucy5wdXNoKGNvbCk7XG5cdFx0fVxuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBncmlkXG5cdFx0bGV0IGdyaWRIdG1sID0gdGhpcy5fd2lkZ2V0SHRtbC5maW5kKGAjJHskLmVzY2FwZVNlbGVjdG9yKHRoaXMuX2RhdGEubmFtZSl9YCk7XG5cblx0XHRncmlkSHRtbC5rZW5kb0dyaWQoe1xuXHRcdFx0cmVzaXphYmxlOiB0cnVlLFxuXHRcdFx0c2VsZWN0YWJsZTogdGhpcy5fZGF0YS5lZGl0YWJsZSA/ICdyb3cnIDogZmFsc2UsXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25HcmlkU2VsZWN0aW9uQ2hhbmdlLCB0aGlzKSxcblx0XHRcdGNvbHVtbnM6IGNvbHVtbnMsXG5cdFx0XHRub1JlY29yZHM6IHtcblx0XHRcdFx0dGVtcGxhdGU6ICdObyBpdGVtcy4nXG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvLyBTYXZlIHJlZi4gdG8gd2lkZ2V0XG5cdFx0dGhpcy5fZ3JpZFdpZGdldCA9IGdyaWRIdG1sLmRhdGEoJ2tlbmRvR3JpZCcpO1xuXG5cdFx0Ly8gU2hvdyB0b290aXAgaWYgZ3JpZCdzIGNlbGwgY29udGVudCBleGNlZWRzIGNlbGwgd2lkdGggKGVsbGlwc2lzIGlzIGRpc3BsYXllZCBieSBLZW5kbyBHcmlkKVxuXHRcdGdyaWRIdG1sLmtlbmRvVG9vbHRpcCh7XG5cdFx0XHRmaWx0ZXI6ICd0ZCcsXG5cdFx0XHRzaG93OiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdC8vIE5ldmVyIHNob3cgdG9vbHRpcC4uLlxuXHRcdFx0XHR0aGlzLmNvbnRlbnQucGFyZW50KCkuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuXG5cdFx0XHRcdC8vIC4uLnVubGVzcyBjb250ZW50IGlzIHJldHVybmVkIChzZWUgYmVsb3cpIGR1ZSB0byBjZWxsIHdpZHRoIGJlaW5nIGV4Y2VlZGVkXG5cdFx0XHRcdGlmICh0aGlzLmNvbnRlbnQudGV4dCgpICE9ICcnKVxuXHRcdFx0XHRcdHRoaXMuY29udGVudC5wYXJlbnQoKS5jc3MoJ3Zpc2liaWxpdHknLCAndmlzaWJsZScpO1xuXHRcdFx0fSxcblx0XHRcdGhpZGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLmNvbnRlbnQucGFyZW50KCkuY3NzKCd2aXNpYmlsaXR5JywgJ2hpZGRlbicpO1xuXHRcdFx0fSxcblx0XHRcdGNvbnRlbnQ6IGZ1bmN0aW9uKGUpIHtcblx0XHRcdFx0bGV0IGVsZW1lbnQgPSBlLnRhcmdldFswXTtcblx0XHRcdFx0aWYgKGVsZW1lbnQub2Zmc2V0V2lkdGggPCBlbGVtZW50LnNjcm9sbFdpZHRoKVxuXHRcdFx0XHRcdHJldHVybiBlLnRhcmdldC50ZXh0KCk7XG5cdFx0XHRcdGVsc2Vcblx0XHRcdFx0XHRyZXR1cm4gJyc7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvKlxuXHRcdC8vIEluaXRpYWxpemUgYnV0dG9uIHRvb2x0aXBzXG5cdFx0dGhpcy5fd2lkZ2V0SHRtbC5rZW5kb1Rvb2x0aXAoe1xuXHRcdFx0ZmlsdGVyOiAnYnV0dG9uJyxcblx0XHRcdGNvbnRlbnQ6IGZ1bmN0aW9uKGUpIHtcblx0XHRcdFx0cmV0dXJuIGA8ZGl2IGNsYXNzPVwiaGVscC10b29sdGlwXCI+JHtlLnRhcmdldC5kYXRhKCd0aXRsZScpfTwvZGl2PmA7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Ki9cblxuXHRcdC8vIEFkZCBidXR0b24gbGlzdGVuZXJzXG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0dGhpcy5fYWRkQnV0dG9uLmNsaWNrKCQucHJveHkodGhpcy5fb25BZGRDbGljaywgdGhpcykpO1xuXHRcdFx0dGhpcy5fZWRpdEJ1dHRvbi5jbGljaygkLnByb3h5KHRoaXMuX29uRWRpdENsaWNrLCB0aGlzKSk7XG5cdFx0XHR0aGlzLl9yZW1vdmVCdXR0b24uY2xpY2soJC5wcm94eSh0aGlzLl9vblJlbW92ZUNsaWNrLCB0aGlzKSk7XG5cdFx0fVxuXG5cdFx0Ly8gUHJvY2VlZCB3aXRoIGluaXRpYWxpemF0aW9uXG5cdFx0c3VwZXIuX2luaXRpYWxpemUoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgZGF0YXNvdXJjZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0bGV0IGRhdGFTb3VyY2UgPSBuZXcga2VuZG8uZGF0YS5EYXRhU291cmNlKHtcblx0XHRcdGRhdGE6IHRoaXMuX2RhdGEubGlzdFZhbHVlc1xuXHRcdH0pO1xuXG5cdFx0Ly8gUmVhZCBjdXJyZW50IGhvcml6b250YWwgc2Nyb2xsIHZhbHVlXG5cdFx0Y29uc3Qgc2Nyb2xsTGVmdCA9ICQoJy5rLWdyaWQtY29udGVudCcsIHRoaXMuX2dyaWRXaWRnZXQud3JhcHBlcikuc2Nyb2xsTGVmdCgpO1xuXG5cdFx0Ly8gQ2xlYXIgZ3JpZCBzZWxlY3Rpb24gaWYgYW55XG5cdFx0dGhpcy5fZ3JpZFdpZGdldC5jbGVhclNlbGVjdGlvbigpO1xuXG5cdFx0Ly8gU2V0IHVwZGF0ZWQgZ3JpZCdzIGRhdGFzb3VyY2Vcblx0XHR0aGlzLl9ncmlkV2lkZ2V0LnNldERhdGFTb3VyY2UoZGF0YVNvdXJjZSk7XG5cblx0XHQvLyBTZXQgaG9yaXpvbnRhbCBzY3JvbGxcblx0XHQkKCcuay1ncmlkLWNvbnRlbnQnLCB0aGlzLl9ncmlkV2lkZ2V0LndyYXBwZXIpLnNjcm9sbExlZnQoc2Nyb2xsTGVmdCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRpc2FibGVkIHN0YXRlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRFZGl0RW5hYmxlZCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQvLyBEZXNlbGVjdCBpdGVtXG5cdFx0XHR0aGlzLl9ncmlkV2lkZ2V0LmNsZWFyU2VsZWN0aW9uKCk7XG5cblx0XHRcdC8vIEVuYWJsZS9kaXNhYmxlIGdyaWRcblx0XHRcdHRoaXMuX2dyaWRXaWRnZXQud3JhcHBlci5hdHRyKCdkaXNhYmxlZCcsICF0aGlzLl9lZGl0RW5hYmxlZCk7XG5cblx0XHRcdC8vIEVuYWJsZSBcIkFkZFwiIGJ1dHRvblxuXHRcdFx0aWYgKHRoaXMuX2VkaXRFbmFibGVkKVxuXHRcdFx0XHR0aGlzLl9hZGRCdXR0b24uYXR0cignZGlzYWJsZWQnLCBmYWxzZSk7XG5cblx0XHRcdC8vIERpc2FibGUgYWxsIGJ1dHRvbnNcblx0XHRcdGVsc2Vcblx0XHRcdHtcblx0XHRcdFx0dGhpcy5fYWRkQnV0dG9uLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cdFx0XHRcdHRoaXMuX2VkaXRCdXR0b24uYXR0cignZGlzYWJsZWQnLCB0cnVlKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQnV0dG9uLmF0dHIoJ2Rpc2FibGVkJywgdHJ1ZSk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0X29uR3JpZFNlbGVjdGlvbkNoYW5nZShlKVxuXHR7XG5cdFx0bGV0IHNlbGVjdGVkUm93cyA9IHRoaXMuX2dyaWRXaWRnZXQuc2VsZWN0KCk7XG5cdFx0bGV0IHNlbGVjdGVkRGF0YUl0ZW1zID0gW107XG5cblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHNlbGVjdGVkUm93cy5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHRsZXQgZGF0YUl0ZW0gPSB0aGlzLl9ncmlkV2lkZ2V0LmRhdGFJdGVtKHNlbGVjdGVkUm93c1tpXSk7XG5cdFx0XHRzZWxlY3RlZERhdGFJdGVtcy5wdXNoKGRhdGFJdGVtKTtcblx0XHR9XG5cblx0XHQvLyBFbmFibGUvZGlzYWJsZSBlZGl0IGJ1dHRvblxuXHRcdGlmICh0aGlzLl9lZGl0QnV0dG9uKVxuXHRcdFx0dGhpcy5fZWRpdEJ1dHRvbi5wcm9wKCdkaXNhYmxlZCcsIHNlbGVjdGVkRGF0YUl0ZW1zLmxlbmd0aCA9PSAwKTtcblxuXHRcdC8vIEVuYWJsZS9kaXNhYmxlIHJlbW92ZSBidXR0b25cblx0XHRpZiAodGhpcy5fcmVtb3ZlQnV0dG9uKVxuXHRcdFx0dGhpcy5fcmVtb3ZlQnV0dG9uLnByb3AoJ2Rpc2FibGVkJywgc2VsZWN0ZWREYXRhSXRlbXMubGVuZ3RoID09IDApO1xuICAgIH1cblxuXHRfb25SZW1vdmVDbGljaygpXG5cdHtcblx0XHRsZXQgc2VsZWN0ZWRJbmRleCA9IHRoaXMuX2dyaWRXaWRnZXQuc2VsZWN0KCkuaW5kZXgoKTtcblxuXHRcdC8vIFJlbW92ZSBpdGVtIGZyb20gbGlzdFxuXHRcdHRoaXMuX2RhdGEucmVtb3ZlTGlzdEl0ZW0oc2VsZWN0ZWRJbmRleCk7XG5cblx0XHQvLyBSZWdlbmVyYXRlIGRhdGFncmlkJ3MgZGF0YXNvdXJjZVxuXHRcdHRoaXMuX3NldFdpZGdldFZhbHVlKCk7XG5cdH1cblxuXHRfb25BZGRDbGljaygpXG5cdHtcblx0XHQvLyBDbG9uZSBkZWZhdWx0IGl0ZW0gYW5kIGFkZCB0byBsaXN0XG5cdFx0bGV0IG5ld0xpc3RJdGVtID0gW107XG5cdFx0Zm9yIChsZXQgc3ViQ1Agb2YgdGhpcy5fZGF0YS5kZWZhdWx0TGlzdEl0ZW0pXG5cdFx0XHRuZXdMaXN0SXRlbS5wdXNoKHN1YkNQLmNsb25lKHRydWUpKTtcblxuXHRcdC8vIENyZWF0ZSBlZGl0IHBvcHVwXG5cdFx0dGhpcy5fb3BlbkVkaXRQYW5lbChuZXdMaXN0SXRlbSk7XG5cdH1cblxuXHRfb25FZGl0Q2xpY2soKVxuXHR7XG5cdFx0bGV0IHNlbGVjdGVkSW5kZXggPSB0aGlzLl9ncmlkV2lkZ2V0LnNlbGVjdCgpLmluZGV4KCk7XG5cblx0XHQvLyBDbG9uZSBzZWxlY3RlZCBpdGVtIGFuZCBhZGQgdG8gbGlzdFxuXHRcdGxldCBjbG9uZWRMaXN0SXRlbSA9IFtdO1xuXHRcdGZvciAobGV0IHN1YkNQIG9mIHRoaXMuX2RhdGEubGlzdEl0ZW1zW3NlbGVjdGVkSW5kZXhdKVxuXHRcdFx0Y2xvbmVkTGlzdEl0ZW0ucHVzaChzdWJDUC5jbG9uZSh0cnVlKSk7XG5cblx0XHQvLyBDcmVhdGUgZWRpdCBwb3B1cFxuXHRcdHRoaXMuX29wZW5FZGl0UGFuZWwoY2xvbmVkTGlzdEl0ZW0sIHNlbGVjdGVkSW5kZXgpO1xuXHR9XG5cblx0X29wZW5FZGl0UGFuZWwoc3ViQ29uZmlnUGFyYW1zQXJyYXksIGVkaXRJbmRleCA9IC0xKVxuXHR7XG5cdFx0Ly8gQ2hlY2sgaWYgdGhpcyBjb25maWd1cmF0aW9uIGl0ZW0gaXMgaW5zaWRlIGEgbW9kYWwgd2luZG93O1xuXHRcdC8vIGlmIHllcywgdGhlIGVkaXQgcGFuZWwgKHdoaWNoIGlzIGEgbW9kYWwgYXMgd2VsbCkgbXVzdCBiZSBjb25maWd1cmVkIHRvIHJlbW92ZSB0aGUgZGFyayBiYWNrZ3JvdW5kXG5cdFx0aWYgKCQodGhpcykucGFyZW50cygnLm1vZGFsJykubGVuZ3RoID4gMClcblx0XHRcdCQoJy5tb2RhbCcsICQodGhpcykpLmF0dHIoJ2RhdGEtYmFja2Ryb3AnLCBmYWxzZSk7XG5cblx0XHQvLyBDcmVhdGUgZGlhbG9nIGNvbnRlbnRcblx0XHR0aGlzLl9pdGVtRWRpdG9yID0gbmV3IExpc3RJdGVtRWRpdG9yKCk7XG5cdFx0dGhpcy5faXRlbUVkaXRvci5kYXRhID0gc3ViQ29uZmlnUGFyYW1zQXJyYXk7XG5cdFx0dGhpcy5faXRlbUVkaXRvci5pbmRleCA9IGVkaXRJbmRleDtcblxuXHRcdGxldCBpdGVtRWRpdG9yID0gJCh0aGlzLl9pdGVtRWRpdG9yKTtcblxuXHRcdC8vIEFwcGVuZCBjb250ZW50IHRvIGRpYWxvZ1xuXHRcdCQoJy5tb2RhbC1ib2R5JywgdGhpcy5fZWRpdERpYWxvZykuYXBwZW5kKGl0ZW1FZGl0b3IpO1xuXG5cdFx0Ly8gU2V0IGRpYWxvZyBtYWluIGJ1dHRvbiB0ZXh0XG5cdFx0JCgnYnV0dG9uLmstcHJpbWFyeScsIHRoaXMuX2VkaXREaWFsb2cpLmh0bWwoZWRpdEluZGV4ID4gLTEgPyAnPGkgY2xhc3M9XCJmYXMgZmEtcGVuIG1yLTFcIj48L2k+VXBkYXRlJyA6ICc8aSBjbGFzcz1cImZhcyBmYS1wbHVzIG1yLTFcIj48L2k+QWRkJyk7XG5cblx0XHQvLyBEaXNwbGF5IGRpYWxvZ1xuXHRcdHRoaXMuX2VkaXREaWFsb2cubW9kYWwoJ3Nob3cnKTtcblx0fVxuXG5cdF9vblN1Ym1pdEJ0Q2xpY2soKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2l0ZW1FZGl0b3IudmFsaWRhdGUoKSlcblx0XHR7XG5cdFx0XHRsZXQgZGF0YSA9IHRoaXMuX2l0ZW1FZGl0b3IuZGF0YTtcblx0XHRcdGxldCBpbmRleCA9IHRoaXMuX2l0ZW1FZGl0b3IuaW5kZXg7XG5cblx0XHRcdC8vIEhpZGUgbW9kYWxcblx0XHRcdHRoaXMuX2VkaXREaWFsb2cubW9kYWwoJ2hpZGUnKTtcblxuXHRcdFx0Ly8gQ29tcGxldGUgZWRpdGluZ1xuXHRcdFx0dGhpcy5fb25FZGl0Q29tcGxldGUoZGF0YSwgaW5kZXgpO1xuXHRcdH1cblx0fVxuXG5cdF9vbkNhbmNlbEJ0Q2xpY2soKVxuXHR7XG5cdFx0Ly8gSGlkZSBtb2RhbFxuXHRcdHRoaXMuX2VkaXREaWFsb2cubW9kYWwoJ2hpZGUnKTtcblx0fVxuXG5cdF9vbkVkaXRQYW5lbEhpZGRlbihlKVxuXHR7XG5cdFx0Ly8gUmVtb3ZlIGNvbnRlbnQgZnJvbSBkaWFsb2dcblx0XHR0aGlzLl9pdGVtRWRpdG9yLnJlbW92ZSgpO1xuXG5cdFx0Ly8gU2V0IGRpYWxvZyBtYWluIGJ1dHRvbiB0ZXh0XG5cdFx0JCgnYnV0dG9uLmstcHJpbWFyeScsIHRoaXMuX2VkaXREaWFsb2cpLmh0bWwoJy4uLicpO1xuXG5cdFx0dGhpcy5faXRlbUVkaXRvciA9IG51bGw7XG5cdH1cblxuXHRfb25FZGl0Q29tcGxldGUobGlzdEl0ZW0sIGVkaXRJbmRleClcblx0e1xuXHRcdC8vIEFuIGV4aXN0aW5nIGxpc3QgaXRlbSB3YXMgdXBkYXRlZFxuXHRcdGlmIChlZGl0SW5kZXggPiAtMSlcblx0XHRcdHRoaXMuX2RhdGEudXBkYXRlTGlzdEl0ZW0obGlzdEl0ZW0sIGVkaXRJbmRleCk7XG5cblx0XHQvLyBBIG5ldyBsaXN0IGl0ZW0gd2FzIGFkZGVkOyBhZGQgaXQgdG8gdGhlIGNvbmZpZ3VyYXRpb24gcGFyYW1ldGVyXG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fZGF0YS5hZGRMaXN0SXRlbShsaXN0SXRlbSk7XG5cblx0XHQvLyBSZWdlbmVyYXRlIGRhdGFncmlkJ3MgZGF0YXNvdXJjZVxuXHRcdHRoaXMuX3NldFdpZGdldFZhbHVlKCk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdjb25maWctZ3JpZCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctZ3JpZCcsIENvbmZpZ0dyaWQpO1xuIiwiZXhwb3J0IGNsYXNzIENvbmZpZ0xhYmVsIGV4dGVuZHMgSFRNTEVsZW1lbnRcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdCAgICBzdXBlcigpO1xuXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywnY29uZmlnLWxhYmVsJyk7XG5cdH1cblxuXHRzZXQgdmFsdWUodmFsKVxuXHR7XG5cdFx0aWYgKHR5cGVvZiB2YWwgPT09ICdib29sZWFuJylcblx0XHRcdHRoaXMuaW5uZXJIVE1MID0gKHZhbCA/ICd0cnVlJyA6ICdmYWxzZScpO1xuXHRcdGVsc2UgaWYgKHR5cGVvZiB2YWwgPT09ICdudW1iZXInKVxuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSAodmFsID8gdmFsIDogMCk7XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5pbm5lckhUTUwgPSAodmFsICE9ICcnID8gdmFsIDogJyZtZGFzaDsnKTtcblx0fVxuXG5cdGdldCB2YWx1ZSgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy50ZXh0Q29udGVudDtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy1sYWJlbCcpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdjb25maWctbGFiZWwnLCBDb25maWdMYWJlbCk7XG4iLCJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuXG5leHBvcnQgY2xhc3MgQ29uZmlnTnVtZXJpY1N0ZXBwZXIgZXh0ZW5kcyBDb25maWdGb3JtSXRlbVxue1xuXHRjb25zdHJ1Y3Rvcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKVxuXHR7XG5cdCAgICBzdXBlcihjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGUgd2lkZ2V0IHRvIHJlbmRlciB0aGUgQ29uZmlnUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBJZiBwYXJhbWV0ZXIgaXMgbm90IGVkaXRhYmxlLCBhIHNpbXBsZSBsYWJlbCBpcyB1c2VkLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9nZW5lcmF0ZUlubmVyV2lkZ2V0KClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdHtcblx0XHRcdC8vIFNldCB3aWRnZXQgY29uZmlndXJhdGlvblxuXHRcdFx0bGV0IGNvbmZpZyA9IHtcblx0XHRcdFx0dHlwZTogJ251bWJlcicsXG5cdFx0XHRcdGNsYXNzOiAnZm9ybS1jb250cm9sJyxcblx0XHRcdFx0aWQ6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdFx0bmFtZTogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHQnZGF0YS1yb2xlJzogJ251bWVyaWN0ZXh0Ym94Jyxcblx0XHRcdFx0J2RhdGEtcmVxdWlyZWQtbXNnJzogJ1JlcXVpcmVkJyxcblx0XHRcdFx0J2RhdGEtZm9ybWF0JzogJyMnLFxuXHRcdFx0XHRyZXF1aXJlZDogJ3JlcXVpcmVkJyxcblx0XHRcdH07XG5cblx0XHRcdC8vIFNldCB3aWRnZXQgYXR0cmlidXRlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldEF0dHJpYnV0ZXMoY29uZmlnKTtcblxuXHRcdFx0Ly8gU2V0IGFkZGl0aW9uYWwgd2lkZ2V0IGF0dHJpYnV0ZXMgYmFzZWQgb24gdmFsaWRhdGlvbiBydWxlcyAoc2VlIHBhcmVudCBjbGFzcylcblx0XHRcdHRoaXMuX3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIENyZWF0ZSB3aWRnZXQncyBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGlucHV0PicsIGNvbmZpZyk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgQ29uZmlnTGFiZWwoKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBJbml0aWFsaXplIHdpZGdldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuICAgX2luaXRpYWxpemUoKVxuICAge1xuXHQgICBpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0ICAge1xuXHRcdCAgIC8vIEluaXRpYWxpemUga2VuZG8gd2lkZ2V0XG5cdFx0ICAga2VuZG8uaW5pdCh0aGlzLl93aWRnZXRIdG1sKTtcblxuXHRcdCAgIC8vIFNhdmUgcmVmLiB0byB3aWRnZXRcblx0XHQgICB0aGlzLl9pbm5lcldpZGdldCA9IHRoaXMuX3dpZGdldEh0bWwuZGF0YSgna2VuZG9OdW1lcmljVGV4dEJveCcpO1xuXG5cdFx0ICAgLy8gRW5hYmxlIHZhbHVlIGNvbW1pdCBiaW5kaW5nXG5cdFx0ICAgdGhpcy5faW5uZXJXaWRnZXQuYmluZCgnY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0ICAgfVxuXG5cdCAgIC8vIFByb2NlZWQgd2l0aCBpbml0aWFsaXphdGlvblxuXHQgICBzdXBlci5faW5pdGlhbGl6ZSgpO1xuICAgfVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIHRoZSBsYWJlbCB0ZXh0IGlzIHNldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl9pbm5lcldpZGdldC52YWx1ZSh0aGlzLl9kYXRhLnZhbHVlKTtcblx0XHRlbHNlXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLnZhbHVlID0gdGhpcy5fZGF0YS52YWx1ZTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgZGlzYWJsZWQgc3RhdGUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X3NldFdpZGdldEVkaXRFbmFibGVkKClcblx0e1xuXHRcdGlmICh0aGlzLl9kYXRhLmVkaXRhYmxlKVxuXHRcdFx0dGhpcy5faW5uZXJXaWRnZXQuZW5hYmxlKHRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSBOdW1iZXIodGhpcy5faW5uZXJXaWRnZXQudmFsdWUoKSk7XG5cblx0XHQvLyBUcmlnZ2VyIGV2ZW50XG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cbn1cblxuLy8gREVGSU5FIENPTVBPTkVOVFxuaWYgKCF3aW5kb3cuY3VzdG9tRWxlbWVudHMuZ2V0KCdjb25maWctbnVtZXJpYy1zdGVwcGVyJykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ2NvbmZpZy1udW1lcmljLXN0ZXBwZXInLCBDb25maWdOdW1lcmljU3RlcHBlcik7XG4iLCJpbXBvcnQge0NvbmZpZ0Zvcm1JdGVtfSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0nO1xuaW1wb3J0IHtDb25maWdMYWJlbH0gZnJvbSAnLi9jb25maWctbGFiZWwnO1xuXG5leHBvcnQgY2xhc3MgQ29uZmlnVGV4dElucHV0IGV4dGVuZHMgQ29uZmlnRm9ybUl0ZW1cbntcblx0Y29uc3RydWN0b3IoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZylcblx0e1xuXHQgICAgc3VwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdH1cblxuXHQvKipcblx0ICogQ3JlYXRlIHdpZGdldCB0byByZW5kZXIgdGhlIENvbmZpZ1BhcmFtZXRlciB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgYSBzaW1wbGUgbGFiZWwgaXMgdXNlZC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfZ2VuZXJhdGVJbm5lcldpZGdldCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQvLyBTZXQgd2lkZ2V0IGNvbmZpZ3VyYXRpb25cblx0XHRcdGxldCBjb25maWcgPSB7XG5cdFx0XHRcdHR5cGU6ICd0ZXh0Jyxcblx0XHRcdFx0Y2xhc3M6ICdmb3JtLWNvbnRyb2wgay10ZXh0Ym94Jyxcblx0XHRcdFx0aWQ6IHRoaXMuX2RhdGEubmFtZSxcblx0XHRcdFx0bmFtZTogdGhpcy5fZGF0YS5uYW1lLFxuXHRcdFx0XHRhdXRvY29tcGxldGU6ICdvZmYnLFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzXG5cdFx0XHR0aGlzLl9zZXRXaWRnZXRBdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIFNldCBhZGRpdGlvbmFsIHdpZGdldCBhdHRyaWJ1dGVzIGJhc2VkIG9uIHZhbGlkYXRpb24gcnVsZXNcblx0XHRcdHRoaXMuX3NldFdpZGdldFZhbGlkYXRpb25BdHRyaWJ1dGVzKGNvbmZpZyk7XG5cblx0XHRcdC8vIENyZWF0ZSB3aWRnZXQncyBodG1sXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sID0gJCgnPGlucHV0PicsIGNvbmZpZyk7XG5cblx0XHRcdC8vIEVuYWJsZSB2YWx1ZSBjb21taXQgYmluZGluZ1xuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbC5vbignY2hhbmdlJywgJC5wcm94eSh0aGlzLl9vblZhbHVlSW5wdXQsIHRoaXMpKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5fd2lkZ2V0SHRtbCA9IG5ldyBDb25maWdMYWJlbCgpO1xuXG5cdFx0Ly8gUmV0dXJuIGNvbXBvbmVudFxuXHRcdHJldHVybiB0aGlzLl93aWRnZXRIdG1sO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyB2YWx1ZS5cblx0ICogSWYgcGFyYW1ldGVyIGlzIG5vdCBlZGl0YWJsZSwgdGhlIGxhYmVsIHRleHQgaXMgc2V0LlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRWYWx1ZSgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsKHRoaXMuX2RhdGEudmFsdWUpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwudmFsdWUgPSB0aGlzLl9kYXRhLnZhbHVlO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldCB3aWRnZXQncyBkaXNhYmxlZCBzdGF0ZS5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0RWRpdEVuYWJsZWQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0XHR0aGlzLl93aWRnZXRIdG1sLmF0dHIoJ2Rpc2FibGVkJywgIXRoaXMuX2VkaXRFbmFibGVkKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBVcGRhdGUgQ29uZmlndXJhdGlvbiBQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X29uVmFsdWVJbnB1dChlKVxuXHR7XG5cdFx0Ly8gVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHRvIG5ldyB2YWx1ZVxuXHRcdHRoaXMuX2RhdGEudmFsdWUgPSB0aGlzLl93aWRnZXRIdG1sLnZhbCgpO1xuXG5cdFx0Ly8gVHJpZ2dlciBldmVudFxuXHRcdHRoaXMuX3RyaWdnZXJFdmVudCgpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnY29uZmlnLXRleHQtaW5wdXQnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLXRleHQtaW5wdXQnLCBDb25maWdUZXh0SW5wdXQpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi9jb25maWctZm9ybS1pdGVtJztcbmltcG9ydCB7Q29uZmlnTGFiZWx9IGZyb20gJy4vY29uZmlnLWxhYmVsJztcbmltcG9ydCB7VmVjdG9yM0RJbnB1dH0gZnJvbSAnLi93aWRnZXRzL3ZlY3Rvci0zZC1pbnB1dCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdWZWN0b3IzRCBleHRlbmRzIENvbmZpZ0Zvcm1JdGVtXG57XG5cdGNvbnN0cnVjdG9yKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpXG5cdHtcblx0ICAgIHN1cGVyKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSB3aWRnZXQgdG8gcmVuZGVyIHRoZSBDb25maWdQYXJhbWV0ZXIgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIGEgc2ltcGxlIGxhYmVsIGlzIHVzZWQuXG5cdCAqIEBvdmVycmlkZVxuXHQgKi9cblx0X2dlbmVyYXRlSW5uZXJXaWRnZXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2RhdGEuZWRpdGFibGUpXG5cdFx0e1xuXHRcdFx0Ly8gQ3JlYXRlIHdpZGdldCdzIGh0bWxcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgVmVjdG9yM0RJbnB1dCh0aGlzLl9kYXRhLm5hbWUsIHRoaXMuX2RhdGEudmFsaWRhdG9yID09ICdhb2knKTtcblxuXHRcdFx0Ly8gU2V0IHdpZGdldCBhdHRyaWJ1dGVzXG5cdFx0XHR0aGlzLl9zZXRXaWRnZXRBdHRyaWJ1dGVzKHRoaXMuX3dpZGdldEh0bWwpO1xuXG5cdFx0XHQvLyBFbmFibGUgdmFsdWUgY29tbWl0IGJpbmRpbmdcblx0XHRcdCQodGhpcy5fd2lkZ2V0SHRtbCkub24oJ2NoYW5nZScsICQucHJveHkodGhpcy5fb25WYWx1ZUlucHV0LCB0aGlzKSk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX3dpZGdldEh0bWwgPSBuZXcgQ29uZmlnTGFiZWwoKTtcblxuXHRcdC8vIFJldHVybiBjb21wb25lbnRcblx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0SHRtbDtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgd2lkZ2V0J3MgdmFsdWUuXG5cdCAqIElmIHBhcmFtZXRlciBpcyBub3QgZWRpdGFibGUsIHRoZSBsYWJlbCB0ZXh0IGlzIHNldC5cblx0ICogQG92ZXJyaWRlXG5cdCAqL1xuXHRfc2V0V2lkZ2V0VmFsdWUoKVxuXHR7XG5cdFx0dGhpcy5fd2lkZ2V0SHRtbC52YWx1ZSA9IHRoaXMuX2RhdGEudmFsdWU7XG5cblx0XHQvLyBUcmlnZ2VyIGV2ZW50XG5cdFx0dGhpcy5fdHJpZ2dlckV2ZW50KCk7XG5cdH1cblxuXHQvKipcblx0ICogU2V0IHdpZGdldCdzIGRpc2FibGVkIHN0YXRlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9zZXRXaWRnZXRFZGl0RW5hYmxlZCgpXG5cdHtcblx0XHRpZiAodGhpcy5fZGF0YS5lZGl0YWJsZSlcblx0XHR7XG5cdFx0XHQkKHRoaXMuX3dpZGdldEh0bWwpLmF0dHIoJ2Rpc2FibGVkJywgIXRoaXMuX2VkaXRFbmFibGVkKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlIENvbmZpZ3VyYXRpb24gUGFyYW1ldGVyIHZhbHVlLlxuXHQgKiBAb3ZlcnJpZGVcblx0ICovXG5cdF9vblZhbHVlSW5wdXQoZSlcblx0e1xuXHRcdC8vIFVwZGF0ZSBDb25maWd1cmF0aW9uIFBhcmFtZXRlciB0byBuZXcgdmFsdWVcblx0XHR0aGlzLl9kYXRhLnZhbHVlID0gdGhpcy5fd2lkZ2V0SHRtbC52YWx1ZTtcblxuXHRcdC8vIFRyaWdnZXIgZXZlbnRcblx0XHR0aGlzLl90cmlnZ2VyRXZlbnQoKTtcblx0fVxufVxuXG4vLyBERUZJTkUgQ09NUE9ORU5UXG5pZiAoIXdpbmRvdy5jdXN0b21FbGVtZW50cy5nZXQoJ2NvbmZpZy12ZWN0b3ItM2QnKSlcblx0d2luZG93LmN1c3RvbUVsZW1lbnRzLmRlZmluZSgnY29uZmlnLXZlY3Rvci0zZCcsIENvbmZpZ1ZlY3RvcjNEKTtcbiIsImltcG9ydCB7Q29uZmlnRm9ybUl0ZW1GYWN0b3J5fSBmcm9tICcuLi8uLi8uLi91dGlscy91aWJ1aWxkZXIvY29uZmlnLWZvcm0taXRlbS1mYWN0b3J5JztcblxuZXhwb3J0IGNsYXNzIExpc3RJdGVtRWRpdG9yIGV4dGVuZHMgSFRNTEVsZW1lbnRcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cdCAgICBzdXBlcigpO1xuXHR9XG5cblx0c2V0IGRhdGEoc3ViQ29uZmlnUGFyYW1zQXJyYXkpXG5cdHtcblx0XHR0aGlzLl9kYXRhID0gc3ViQ29uZmlnUGFyYW1zQXJyYXk7XG5cblx0XHR0aGlzLl9idWlsZFZpZXcoKTtcblx0fVxuXG5cdGdldCBkYXRhKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9kYXRhO1xuXHR9XG5cblx0c2V0IGluZGV4KGluZGV4KVxuXHR7XG5cdFx0dGhpcy5faW5kZXggPSBpbmRleDtcblx0fVxuXG5cdGdldCBpbmRleCgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5faW5kZXg7XG5cdH1cblxuXHRfYnVpbGRWaWV3KClcblx0e1xuXHRcdC8vIEdlbmVyYXRlIGNvbnRhaW5lciBmb3JtXG5cdFx0dGhpcy5fZm9ybSA9ICQoJzxmb3JtPicsIHt9KTtcblxuXHRcdC8vIEFwcGVuZCBmb3JtXG5cdFx0JCh0aGlzKS5hcHBlbmQodGhpcy5fZm9ybSk7XG5cblx0XHQvLyBHZW5lcmF0ZSBmb3JtIGZpZWxkc1xuXHRcdGZvciAobGV0IGNvbmZpZ1BhcmFtIG9mIHRoaXMuX2RhdGEpXG5cdFx0e1xuXHRcdFx0Ly8gQ3JlYXRlIGZvcm0gaXRlbVxuXHRcdFx0bGV0IGZvcm1JdGVtID0gQ29uZmlnRm9ybUl0ZW1GYWN0b3J5LmNyZWF0ZShjb25maWdQYXJhbSwgdHJ1ZSwgdHJ1ZSk7XG5cdFx0XHRmb3JtSXRlbS5kYXRhID0gY29uZmlnUGFyYW07XG5cblx0XHRcdC8vIEFkZCBmb3JtIGl0ZW0gdG8gZm9ybVxuXHRcdFx0dGhpcy5fZm9ybS5hcHBlbmQoZm9ybUl0ZW0pO1xuXHRcdH1cblxuXHRcdC8vIEluaXRpYWxpemUga2VuZG8gdmFsaWRhdGlvbiBvbiBmb3JtXG5cdFx0dGhpcy5fdmFsaWRhdG9yID0gdGhpcy5fZm9ybS5rZW5kb1ZhbGlkYXRvcih7XG5cdFx0XHR2YWxpZGF0ZU9uQmx1cjogdHJ1ZSxcblx0XHRcdHJ1bGVzOiB7XG5cdFx0XHRcdC8vIEFkZCBydWxlIHRvIHZhbGlkYXRlIEFPSSBmb3JtIGl0ZW1zP1xuXHRcdFx0XHQvLyAoc2VlOiBodHRwczovL2RlbW9zLnRlbGVyaWsuY29tL2tlbmRvLXVpL3ZhbGlkYXRvci9jdXN0b20tdmFsaWRhdGlvbilcblx0XHRcdFx0YW9pOiBmdW5jdGlvbiAoaW5wdXQpIHtcblx0XHRcdFx0XHRpZiAoaW5wdXQuaXMoJ1tkYXRhLWFvaS1tc2ddJykgJiYgaW5wdXQudmFsKCkgIT0gJycpXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0aWYgKGlucHV0LnZhbCgpID09ICcwLDAsMCcpXG5cdFx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH1cblx0XHRcdH1cblx0XHR9KS5kYXRhKCdrZW5kb1ZhbGlkYXRvcicpO1xuXHR9XG5cblx0dmFsaWRhdGUoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbGlkYXRvci52YWxpZGF0ZSgpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgnbGlzdC1pdGVtLWVkaXRvcicpKVxuXHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKCdsaXN0LWl0ZW0tZWRpdG9yJywgTGlzdEl0ZW1FZGl0b3IpO1xuIiwiZXhwb3J0IGNsYXNzIFZlY3RvcjNESW5wdXQgZXh0ZW5kcyBIVE1MRWxlbWVudFxue1xuXHRjb25zdHJ1Y3RvcihpZCwgaXNWYWxpZGFibGUpXG5cdHtcblx0ICAgIHN1cGVyKCk7XG5cblx0XHR0aGlzLmlkID0gaWQ7XG5cdFx0dGhpcy5uYW1lID0gaWQ7XG5cblx0XHR0aGlzLl9pc1ZhbGlkYWJsZSA9IGlzVmFsaWRhYmxlO1xuXG5cdFx0dGhpcy5faW5pdGlhbGl6ZSgpO1xuXHR9XG5cblx0c2V0IGVuYWJsZUNsZWFyKHZhbHVlKVxuXHR7XG5cdFx0aWYgKHZhbHVlKVxuXHRcdFx0dGhpcy5fY2xlYXJCdXR0b24uc2hvdygpO1xuXHRcdGVsc2Vcblx0XHRcdHRoaXMuX2NsZWFyQnV0dG9uLmhpZGUoKTtcblx0fVxuXG5cdHNldCBhbGxvd05lZ2F0aXZlKHZhbHVlKVxuXHR7XG5cdFx0aWYgKHZhbHVlKVxuXHRcdHtcblx0XHRcdHRoaXMuX3dpZGdldFguc2V0T3B0aW9ucygge21pbjogbnVsbH0gKTtcblx0XHRcdHRoaXMuX3dpZGdldFkuc2V0T3B0aW9ucygge21pbjogbnVsbH0gKTtcblx0XHRcdHRoaXMuX3dpZGdldFouc2V0T3B0aW9ucygge21pbjogbnVsbH0gKTtcblx0XHR9XG5cdH1cblxuXHRzZXQgdmFsdWUodmFsKVxuXHR7XG5cdFx0dmFyIGNvb3JkcyA9IHZhbC5zcGxpdCgnLCcpO1xuXG5cdFx0aWYgKGNvb3Jkcy5sZW5ndGggPj0gMSlcblx0XHRcdHRoaXMuX3dpZGdldFgudmFsdWUoY29vcmRzWzBdKTtcblxuXHRcdGlmIChjb29yZHMubGVuZ3RoID49IDIpXG5cdFx0XHR0aGlzLl93aWRnZXRZLnZhbHVlKGNvb3Jkc1sxXSk7XG5cblx0XHRpZiAoY29vcmRzLmxlbmd0aCA+PSAzKVxuXHRcdFx0dGhpcy5fd2lkZ2V0Wi52YWx1ZShjb29yZHNbMl0pO1xuXG5cdFx0aWYgKHRoaXMuX2lzVmFsaWRhYmxlKVxuXHRcdFx0dGhpcy5faW5wdXRWYWwudmFsKHRoaXMudmFsdWUpO1xuXHR9XG5cblx0Z2V0IHZhbHVlKClcblx0e1xuXHRcdGlmICh0aGlzLl93aWRnZXRYLnZhbHVlKCkgPT0gbnVsbCAmJiB0aGlzLl93aWRnZXRZLnZhbHVlKCkgPT0gbnVsbCAmJiB0aGlzLl93aWRnZXRaLnZhbHVlKCkgPT0gbnVsbClcblx0XHRcdHJldHVybiAnJztcblx0XHRlbHNlXG5cdFx0XHRyZXR1cm4gdGhpcy5fd2lkZ2V0WC52YWx1ZSgpICsgJywnICsgdGhpcy5fd2lkZ2V0WS52YWx1ZSgpICsgJywnICsgdGhpcy5fd2lkZ2V0Wi52YWx1ZSgpO1xuXHR9XG5cblx0X2luaXRpYWxpemUoKVxuXHR7XG5cdFx0Ly8gR2VuZXJhdGUgY29udGFpbmVyIGZvcm1cblx0XHR0aGlzLl9jb250YWluZXIgPSAkKCc8ZGl2PicsIHtcblx0XHRcdGNsYXNzOiAnZm9ybS1pbmxpbmUnXG5cdFx0fSk7XG5cblx0XHQvLyBBcHBlbmQgY29udGFpbmVyXG5cdFx0JCh0aGlzKS5hcHBlbmQodGhpcy5fY29udGFpbmVyKTtcblxuXHRcdC8vIFNldCBpbnB1dHMgY29uZmlndXJhdGlvblxuXHRcdGxldCBjb25maWdIdG1sID0ge1xuXHRcdFx0dHlwZTogJ251bWJlcicsXG5cdFx0XHRjbGFzczogJ2Zvcm0tY29udHJvbCBzaG9ydC00Jyxcblx0XHR9O1xuXG5cdFx0Ly8gU2V0IHdpZGdldCBjb25maWd1cmF0aW9uXG5cdFx0bGV0IGNvbmZpZ1dpZGdldCA9IHtcblx0XHRcdG1pbjogMCxcblx0XHRcdHNwaW5uZXJzOiBmYWxzZSxcblx0XHRcdGZvcm1hdDogJyMuIyMjIyMjJyxcblx0XHRcdGRlY2ltYWxzOiA2LFxuXHRcdFx0cm91bmQ6IGZhbHNlLFxuXHRcdFx0c3Bpbm5lcnM6IGZhbHNlLFxuXHRcdFx0cmVzdHJpY3REZWNpbWFsczogZmFsc2UsXG5cdFx0XHRjaGFuZ2U6ICQucHJveHkodGhpcy5fb25DaGFuZ2UsIHRoaXMpXG5cdFx0fTtcblxuXHRcdC8vIENyZWF0ZSB3aWRnZXRzXG5cdFx0dGhpcy5faW5wdXRYID0gJCgnPGlucHV0PicsIGNvbmZpZ0h0bWwpO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQodGhpcy5faW5wdXRYKTtcblx0XHR0aGlzLl93aWRnZXRYID0gdGhpcy5faW5wdXRYLmtlbmRvTnVtZXJpY1RleHRCb3goY29uZmlnV2lkZ2V0KS5kYXRhKCdrZW5kb051bWVyaWNUZXh0Qm94Jyk7XG5cblx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKCc8c3BhbiBjbGFzcz1cInB4LTFcIj4sPC9zcGFuPicpO1xuXG5cdFx0dGhpcy5faW5wdXRZID0gJCgnPGlucHV0PicsIGNvbmZpZ0h0bWwpO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQodGhpcy5faW5wdXRZKTtcblx0XHR0aGlzLl93aWRnZXRZID0gdGhpcy5faW5wdXRZLmtlbmRvTnVtZXJpY1RleHRCb3goY29uZmlnV2lkZ2V0KS5kYXRhKCdrZW5kb051bWVyaWNUZXh0Qm94Jyk7XG5cblx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKCc8c3BhbiBjbGFzcz1cInB4LTFcIj4sPC9zcGFuPicpO1xuXG5cdFx0dGhpcy5faW5wdXRaID0gJCgnPGlucHV0PicsIGNvbmZpZ0h0bWwpO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmQodGhpcy5faW5wdXRaKTtcblx0XHR0aGlzLl93aWRnZXRaID0gdGhpcy5faW5wdXRaLmtlbmRvTnVtZXJpY1RleHRCb3goY29uZmlnV2lkZ2V0KS5kYXRhKCdrZW5kb051bWVyaWNUZXh0Qm94Jyk7XG5cblx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKCc8c3BhbiBjbGFzcz1cInB4LTFcIj48L3NwYW4+Jyk7IC8vIEFkZGl0aW9uYWwgc3BhY2VyXG5cblx0XHQvLyBDcmVhdGUgaW52aXNpYmxlIGZpZWxkIHRvIGFwcGx5IG92ZXJhbGwgdmFsaWRhdGlvblxuXHRcdGlmICh0aGlzLl9pc1ZhbGlkYWJsZSlcblx0XHR7XG5cdFx0XHR0aGlzLl9pbnB1dFZhbCA9ICQoJzxpbnB1dD4nLCB7bmFtZTogYCR7dGhpcy5uYW1lfS1jdXN0b20tdmFsaWRhdGVgLCAnZGF0YS1hb2ktbXNnJzogJ1ZhbHVlcyBjYW5cXCd0IGFsbCBiZSAwJ30pO1xuXHRcdFx0dGhpcy5fY29udGFpbmVyLmFwcGVuZCh0aGlzLl9pbnB1dFZhbCk7XG5cdFx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKGA8c3BhbiBjbGFzcz1cImstaW52YWxpZC1tc2dcIiBkYXRhLWZvcj1cIiR7dGhpcy5uYW1lfS1jdXN0b20tdmFsaWRhdGVcIj48L3NwYW4+YClcblx0XHRcdHRoaXMuX2lucHV0VmFsLmhpZGUoKTtcblx0XHR9XG5cblx0XHQvLyBDcmVhdGUgYW5kIGFwcGVuZCBDbGVhciBidXR0b25cblx0XHR0aGlzLl9jbGVhckJ1dHRvbiA9ICQoJzxidXR0b24+Jywge3R5cGU6ICdidXR0b24nLCBjbGFzczogJ2stYnV0dG9uIGstc2Vjb25kYXJ5IG15LTEnLCB0aXRsZTogJ0NsZWFyJ30pLmFwcGVuZCgkKCc8aSBjbGFzcz1cImZhcyBmYS10aW1lc1wiPjwvaT4nKSk7XG5cdFx0dGhpcy5fY2xlYXJCdXR0b24ub24oJ2NsaWNrJywgJC5wcm94eSh0aGlzLl9vbkNsZWFyQ2xpY2ssIHRoaXMpKTtcblx0XHR0aGlzLl9jb250YWluZXIuYXBwZW5kKHRoaXMuX2NsZWFyQnV0dG9uKTtcblxuXHRcdC8vIEhpZGUgYnV0dG9uIGJ5IGRlZmF1bHRcblx0XHR0aGlzLl9jbGVhckJ1dHRvbi5oaWRlKCk7XG5cdH1cblxuXHRfb25DaGFuZ2UoKVxuXHR7XG5cdFx0Ly8gRW1wdHkgc3RyaW5ncyBhcmUgbm90IGFsbG93ZWRcblx0XHRpZiAodGhpcy5fd2lkZ2V0WC52YWx1ZSgpID09IG51bGwpXG5cdFx0XHR0aGlzLl93aWRnZXRYLnZhbHVlKDApO1xuXG5cdFx0aWYgKHRoaXMuX3dpZGdldFkudmFsdWUoKSA9PSBudWxsKVxuXHRcdFx0dGhpcy5fd2lkZ2V0WS52YWx1ZSgwKTtcblxuXHRcdGlmICh0aGlzLl93aWRnZXRaLnZhbHVlKCkgPT0gbnVsbClcblx0XHRcdHRoaXMuX3dpZGdldFoudmFsdWUoMCk7XG5cblx0XHR0aGlzLl9kaXNwYXRjaENvbW1pdCgpO1xuXHR9XG5cblx0X29uQ2xlYXJDbGljaygpXG5cdHtcblx0XHR0aGlzLl93aWRnZXRYLnZhbHVlKCcnKTtcblx0XHR0aGlzLl93aWRnZXRZLnZhbHVlKCcnKTtcblx0XHR0aGlzLl93aWRnZXRaLnZhbHVlKCcnKTtcblxuXHRcdHRoaXMuX2Rpc3BhdGNoQ29tbWl0KCk7XG5cdH1cblxuXHRfZGlzcGF0Y2hDb21taXQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX2lzVmFsaWRhYmxlKVxuXHRcdFx0dGhpcy5faW5wdXRWYWwudmFsKHRoaXMudmFsdWUpO1xuXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnY2hhbmdlJykpO1xuXHR9XG59XG5cbi8vIERFRklORSBDT01QT05FTlRcbmlmICghd2luZG93LmN1c3RvbUVsZW1lbnRzLmdldCgndmVjdG9yLTNkLWlucHV0JykpXG5cdHdpbmRvdy5jdXN0b21FbGVtZW50cy5kZWZpbmUoJ3ZlY3Rvci0zZC1pbnB1dCcsIFZlY3RvcjNESW5wdXQpO1xuIiwiaW1wb3J0IHtDb25maWdGb3JtSXRlbX0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLWZvcm0taXRlbSc7XG5cbmltcG9ydCB7Q29uZmlnTnVtZXJpY1N0ZXBwZXJ9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1udW1lcmljLXN0ZXBwZXInO1xuaW1wb3J0IHtDb25maWdUZXh0SW5wdXR9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy10ZXh0LWlucHV0JztcbmltcG9ydCB7Q29uZmlnQ2hlY2tCb3h9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1jaGVjay1ib3gnO1xuaW1wb3J0IHtDb25maWdEcm9wRG93bkxpc3R9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1kcm9wLWRvd24tbGlzdCc7XG5pbXBvcnQge0NvbmZpZ0dyaWR9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1ncmlkJztcbmltcG9ydCB7Q29uZmlnRHVhbExpc3R9IGZyb20gJy4uLy4uL2NvbXBvbmVudHMvdWlidWlsZGVyL2NvbmZpZy1kdWFsLWxpc3QnO1xuaW1wb3J0IHtDb25maWdWZWN0b3IzRH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy91aWJ1aWxkZXIvY29uZmlnLXZlY3Rvci0zZCc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdGb3JtSXRlbUZhY3Rvcnlcbntcblx0c3RhdGljIGNyZWF0ZShjb25maWdQYXJhbSwgZWRpdEVuYWJsZWQsIGluRGlhbG9nID0gZmFsc2UpXG5cdHtcblx0XHRzd2l0Y2ggKGNvbmZpZ1BhcmFtLnR5cGUpXG5cdFx0e1xuXHRcdFx0Y2FzZSAnVGV4dElucHV0Jzpcblx0XHRcdFx0cmV0dXJuIG5ldyBDb25maWdUZXh0SW5wdXQoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdDaGVja0JveCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnQ2hlY2tCb3goY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdOdW1lcmljU3RlcHBlcic6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnTnVtZXJpY1N0ZXBwZXIoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdDb21ib0JveCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnRHJvcERvd25MaXN0KGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnRGF0YUdyaWQnOlxuXHRcdFx0XHRyZXR1cm4gbmV3IENvbmZpZ0dyaWQoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdEdWFsTGlzdCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnRHVhbExpc3QoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdWZWN0b3IzRCc6XG5cdFx0XHRcdHJldHVybiBuZXcgQ29uZmlnVmVjdG9yM0QoY29uZmlnUGFyYW0sIGVkaXRFbmFibGVkLCBpbkRpYWxvZyk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRyZXR1cm4gbmV3IENvbmZpZ0Zvcm1JdGVtKGNvbmZpZ1BhcmFtLCBlZGl0RW5hYmxlZCwgaW5EaWFsb2cpOyAvLyBXaWxsIGxvZyBhbiBlcnJvciBmb3IgbWlzc2luZyBmb3JtIGl0ZW0gdHlwZVxuXHRcdH1cblx0fVxufVxuIiwiaW1wb3J0IHtDb25maWd1cmF0aW9uUGFyYW1ldGVyfSBmcm9tICcuL2NvbmZpZ3VyYXRpb24tcGFyYW1ldGVyJztcbmltcG9ydCB7Q29uZmlnRm9ybUl0ZW1GYWN0b3J5fSBmcm9tICcuL2NvbmZpZy1mb3JtLWl0ZW0tZmFjdG9yeSc7XG5cbmV4cG9ydCBjbGFzcyBDb25maWdJbnRlcmZhY2VCdWlsZGVyXG57XG5cdGNvbnN0cnVjdG9yKClcblx0e1xuXHRcdC8vIFNldCBzb21lIGNvbnN0YW50c1xuXHRcdHRoaXMuVEFCX1BSRUZJWCA9ICd0YWItJ1xuXHRcdHRoaXMuVEFCX1BBTkVfUFJFRklYID0gJ3RhYnBhbmUtJztcblx0XHR0aGlzLlNFUEFSQVRPUl9CRUZPUkUgPSAnYmVmb3JlJztcblx0XHR0aGlzLlNFUEFSQVRPUl9BRlRFUiA9ICdhZnRlcic7XG5cdH1cblxuXHRkdW1wKG1vZGlmaWVkT25seSA9IGZhbHNlKVxuXHR7XG5cdFx0bGV0IGR1bXBTdHIgPSAnJztcblxuXHRcdGZvciAobGV0IGNwIG9mIHRoaXMuX2NvbmZpZ1BhcmFtcylcblx0XHR7XG5cdFx0XHRpZiAobW9kaWZpZWRPbmx5KVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoY3AuaXNNb2RpZmllZClcblx0XHRcdFx0XHRkdW1wU3RyICs9IGNwLnRvU3RyaW5nKCkgKyAnXFxuJztcblx0XHRcdH1cblx0XHRcdGVsc2Vcblx0XHRcdFx0ZHVtcFN0ciArPSBjcC50b1N0cmluZygpICsgJ1xcbic7XG5cdFx0fVxuXG5cdFx0Y29uc29sZS5sb2coZHVtcFN0cik7XG5cdH1cblxuXHRidWlsZEludGVyZmFjZShkYXRhLCBtYWluQ29udGFpbmVySWQsIGRpc2FibGVFZGl0ID0gZmFsc2UsIHRhYlN1ZmZpeCA9ICcnKVxuXHR7XG5cdFx0dGhpcy5fbWFpbkNvbnRhaW5lcklkID0gbWFpbkNvbnRhaW5lcklkO1xuXHRcdHRoaXMuX2NvbmZpZ1BhcmFtcyA9IG5ldyBBcnJheSgpO1xuXHRcdHRoaXMuX3ZhbGlkYXRvciA9IG51bGw7XG5cblx0XHRsZXQgaGFzTmV3Rm9ybUl0ZW0gPSBmYWxzZTtcblxuXHRcdC8vY29uc29sZS5sb2coZGF0YS5nZXREdW1wKCkpXG5cblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IGRhdGEuc2l6ZSgpOyBpKyspXG5cdFx0e1xuXHRcdFx0Ly8gUEFSU0UgREFUQVxuXG5cdFx0XHRsZXQgY29uZmlnUGFyYW0gPSBDb25maWd1cmF0aW9uUGFyYW1ldGVyLmZyb21TZnNPYmplY3QoZGF0YS5nZXQoaSkpO1xuXHRcdFx0dGhpcy5fY29uZmlnUGFyYW1zLnB1c2goY29uZmlnUGFyYW0pO1xuXG5cdFx0XHQvLyBHZXQgdGFiIGFuZCB0YWIgcGFuZSBpZCBmcm9tIGdyb3VwIGlkXG5cdFx0XHRjb25zdCB0YWJJZCA9IHRoaXMuVEFCX1BSRUZJWCArIGNvbmZpZ1BhcmFtLmNhdGVnb3J5SWQgKyAodGFiU3VmZml4ID8gJ18nICsgdGFiU3VmZml4IDogJycpO1xuXHRcdFx0Y29uc3QgdGFiUGFuZUlkID0gdGhpcy5UQUJfUEFORV9QUkVGSVggKyBjb25maWdQYXJhbS5jYXRlZ29yeUlkICsgKHRhYlN1ZmZpeCA/ICdfJyArIHRhYlN1ZmZpeCA6ICcnKTtcblxuXHRcdFx0Ly8gQlVJTEQgSU5URVJGQUNFIDo6IFRBQlNcblxuXHRcdFx0Ly8gQ2hlY2sgaWYgYSB0YWIgc3BlY2lmaWMgZm9yIHRoaXMgZ3JvdXAgYWxyZWFkeSBleGlzdHMgaW5zaWRlIHRoZSBtYWluQ29udGFpbmVyOiBpZiBub3QsIGNyZWF0ZSBpdFxuXHRcdFx0Ly8gKGEgdGFiIGFscmVhZHkgZXhpc3RzIGlmIGl0IHdhcyBjcmVhdGVkIGluIGEgcHJldmlvdXMgbG9vcClcblx0XHRcdGxldCB0YWIgPSAkKGAjJHttYWluQ29udGFpbmVySWR9ID4gI3RhYnMgIyR7dGFiSWR9YCk7XG5cblx0XHRcdGlmICh0YWIubGVuZ3RoID09IDApXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENyZWF0ZSB0YWIgZm9yIHRhYiBwYW5lXG5cdFx0XHRcdHRhYiA9ICQoJzxsaT4nLCB7Y2xhc3M6ICduYXYtaXRlbSd9KTtcblx0XHRcdFx0dGFiLmFwcGVuZCgkKCc8YT4nLCB7XG5cdFx0XHRcdFx0Y2xhc3M6ICduYXYtbGluaycgKyAoaSA9PSAwID8gJyBhY3RpdmUnIDogJycpLFxuXHRcdFx0XHRcdGlkOiB0YWJJZCxcblx0XHRcdFx0XHQnZGF0YS10b2dnbGUnOiAndGFiJyxcblx0XHRcdFx0XHRocmVmOiAnIycgKyB0YWJQYW5lSWQsXG5cdFx0XHRcdFx0cm9sZTogJ3RhYicsXG5cdFx0XHRcdFx0J2FyaWEtY29udHJvbHMnOiB0YWJQYW5lSWQsXG5cdFx0XHRcdFx0J2FyaWEtc2VsZWN0ZWQnOiAoaSA9PSAwID8gJ3RydWUnIDogJ2ZhbHNlJyksXG5cdFx0XHRcdFx0aHRtbDogY29uZmlnUGFyYW0uY2F0ZWdvcnksXG5cdFx0XHRcdH0pKTtcblxuXHRcdFx0XHQvLyBBZGQgdGFiIHRvIGNvbnRhaW5lclxuXHRcdFx0XHQkKGAjJHttYWluQ29udGFpbmVySWR9ID4gI3RhYnNgKS5hcHBlbmQodGFiKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQlVJTEQgSU5URVJGQUNFIDo6IFRBQiBQQU5FU1xuXG5cdFx0XHQvLyBDaGVjayBpZiBhIHRhYiBwYW5lIHNwZWNpZmljIGZvciB0aGlzIGdyb3VwIGFscmVhZHkgZXhpc3RzIGluc2lkZSB0aGUgbWFpbkNvbnRhaW5lcjogaWYgbm90LCBjcmVhdGUgaXRcblx0XHRcdC8vIChhIHRhYiBwYW5lIGFscmVhZHkgZXhpc3RzIGlmIGl0IHdhcyBjcmVhdGVkIGluIGEgcHJldmlvdXMgbG9vcCBvciBpZiBpdCBleGlzdHMgc3RhdGljYWxseSBpbiB0aGUgaHRtbCAtIGluIGNhc2UgaXQgaXMgbmVlZGVkIHRvIGFkZCBzb21lIHN0YXRpYyBjb250ZW50KVxuXHRcdFx0bGV0IHRhYlBhbmUgPSAkKGAjJHttYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+ICMke3RhYlBhbmVJZH1gKTtcblxuXHRcdFx0aWYgKHRhYlBhbmUubGVuZ3RoID09IDApXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENyZWF0ZSB0YWIgcGFuZVxuXHRcdFx0XHR0YWJQYW5lID0gJCgnPGRpdj4nLCB7XG5cdFx0XHRcdFx0Y2xhc3M6ICd0YWItcGFuZScgKyAoaSA9PSAwID8gJyBzaG93IGFjdGl2ZScgOiAnJyksXG5cdFx0XHRcdFx0aWQ6IHRhYlBhbmVJZCxcblx0XHRcdFx0XHRyb2xlOiAndGFicGFuZWwnLFxuXHRcdFx0XHRcdCdhcmlhLWxhYmVsbGVkYnknOiB0YWJJZCxcblx0XHRcdFx0XHQnZGF0YS1keW5hbWljJzogJ3RydWUnLFxuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHQvLyBBZGQgdGFiIHBhbmUgdG8gY29udGFpbmVyXG5cdFx0XHRcdCQoYCMke21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzYCkuYXBwZW5kKHRhYlBhbmUpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBCVUlMRCBJTlRFUkZBQ0UgOjogVEFCIFBBTkVTJyBGT1JNXG5cblx0XHRcdC8vIENoZWNrIGlmIGEgZm9ybSBhbHJlYWR5IGV4aXN0cyBpbnNpZGUgdGhlIHRhYiBwYW5lOiBpZiBub3QsIGNyZWF0ZSBpdFxuXHRcdFx0bGV0IGZvcm0gPSB0YWJQYW5lLmZpbmQoJ2Zvcm0nKTtcblxuXHRcdFx0aWYgKGZvcm0ubGVuZ3RoID09IDApXG5cdFx0XHR7XG5cdFx0XHRcdC8vIENyZWF0ZSBmb3JtXG5cdFx0XHRcdGZvcm0gPSAkKCc8Zm9ybT4nLCB7XG5cdFx0XHRcdFx0Y2xhc3M6ICcnLFxuXHRcdFx0XHRcdGF1dG9jb21wbGV0ZTogJ29mZidcblx0XHRcdFx0fSk7XG5cblx0XHRcdFx0Ly8gQ3JlYXRlIGFuIGlubmVyIGZpZWxkc2V0OyB0aGlzIG1pZ2h0IGJlIHVzZWZ1bCB0byBlYXNpbHkgZGlzYWJsZSB0aGUgd2hvbGUgZm9ybSBhdCBvbmNlIChhY3R1YWxseSB3ZSBkb24ndCB1c2UgaXQgYmVjYXVzZSBLZW5kbyB3aWRnZXRzIGFyZSBub3QgZGlzYWJsZWQgYXV0b21hdGljYWxseSlcblx0XHRcdFx0Zm9ybS5hcHBlbmQoXG5cdFx0XHRcdFx0JCgnPGZpZWxkc2V0PicsIHtcblx0XHRcdFx0XHRcdGNsYXNzOiAnJ1xuXHRcdFx0XHRcdH0pXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0Ly8gQWRkIGZvcm0gdG8gdGFiIHBhbmVcblx0XHRcdFx0dGFiUGFuZS5wcmVwZW5kKGZvcm0pO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBHZXQgZmllbGRzZXQsIHdoaWNoIGlzIHRoZSBhY3R1YWwgZm9ybSBpdGVtcyBjb250YWluZXJcblx0XHRcdGxldCBmaWVsZHNldCA9IGZvcm0uZmluZCgnZmllbGRzZXQnKTtcblxuXHRcdFx0Ly8gQlVJTEQgSU5URVJGQUNFIDo6IFRBQiBQQU5FUycgRk9STSBJVEVNU1xuXG5cdFx0XHQvLyBDaGVjayBpZiBmb3JtIGl0ZW0gYWxyZWFkeSBleGlzdHMgaW4gZmllbGRzZXQ7IGlmIHllcywganVzdCB1cGRhdGUgaXRzIGRhdGFcblx0XHRcdGxldCBmb3JtSXRlbSA9IGZpZWxkc2V0LmZpbmQoYCNmb3JtLWl0ZW0tJHskLmVzY2FwZVNlbGVjdG9yKGNvbmZpZ1BhcmFtLm5hbWUpfWApO1xuXG5cdFx0XHRpZiAoZm9ybUl0ZW0ubGVuZ3RoID09IDApXG5cdFx0XHR7XG5cdFx0XHRcdGhhc05ld0Zvcm1JdGVtID0gdHJ1ZTtcblxuXHRcdFx0XHRmb3JtSXRlbSA9IENvbmZpZ0Zvcm1JdGVtRmFjdG9yeS5jcmVhdGUoY29uZmlnUGFyYW0sICFkaXNhYmxlRWRpdCk7XG5cblx0XHRcdFx0Ly8gQWRkIHNlcGFyYXRvciBiZWZvcmVcblx0XHRcdFx0aWYgKGNvbmZpZ1BhcmFtLnNlcGFyYXRvciAhPSBudWxsICYmIGNvbmZpZ1BhcmFtLnNlcGFyYXRvci5wb3MgPT0gJ2JlZm9yZScpXG5cdFx0XHRcdFx0ZmllbGRzZXQuYXBwZW5kKHRoaXMuX2J1aWxkU2VwYXJhdG9yKGNvbmZpZ1BhcmFtLnNlcGFyYXRvcikpO1xuXG5cdFx0XHRcdC8vIEFkZCBmb3JtIGl0ZW0gdG8gZm9ybVxuXHRcdFx0XHRmaWVsZHNldC5hcHBlbmQoZm9ybUl0ZW0pO1xuXG5cdFx0XHRcdC8vIEFkZCBzZXBhcmF0b3IgYWZ0ZXJcblx0XHRcdFx0aWYgKGNvbmZpZ1BhcmFtLnNlcGFyYXRvciAhPSBudWxsICYmIGNvbmZpZ1BhcmFtLnNlcGFyYXRvci5wb3MgPT0gJ2FmdGVyJylcblx0XHRcdFx0XHRmaWVsZHNldC5hcHBlbmQodGhpcy5fYnVpbGRTZXBhcmF0b3IoY29uZmlnUGFyYW0uc2VwYXJhdG9yKSk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlXG5cdFx0XHRcdGZvcm1JdGVtWzBdLmRhdGEgPSBjb25maWdQYXJhbTtcblx0XHR9XG5cblx0XHQvLyBBZGQgbGlzdGVuZXIgdG8gc2hvdyBoZWxwIHRvb2x0aXBzXG5cdFx0bGV0IGFsbFRhYlBhbmVzID0gJChgIyR7bWFpbkNvbnRhaW5lcklkfSA+ICN0YWJQYW5lbHMgPiBkaXYudGFiLXBhbmVgKTtcblx0XHRhbGxUYWJQYW5lcy5rZW5kb1Rvb2x0aXAoe1xuXHRcdFx0ZmlsdGVyOiAnaVt0aXRsZV0uaGVscCcsXG5cdFx0XHRwb3NpdGlvbjogJ3JpZ2h0Jyxcblx0XHRcdHdpZHRoOiAnMjUwcHgnLFxuXHRcdFx0Y29udGVudDogZnVuY3Rpb24oZSkge1xuXHRcdFx0XHRyZXR1cm4gYDxkaXYgY2xhc3M9XCJoZWxwLXRvb2x0aXBcIj4ke2UudGFyZ2V0LmRhdGEoJ3RpdGxlJyl9PC9kaXY+YDtcblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdC8vIEluaXRpYWxpemUga2VuZG8gdmFsaWRhdGlvbiBvbiBmb3JtcycgbWFpbiBjb250YWluZXJcblx0XHR0aGlzLl92YWxpZGF0b3IgPSAkKGAjJHttYWluQ29udGFpbmVySWR9YCkua2VuZG9WYWxpZGF0b3Ioe1xuXHRcdFx0dmFsaWRhdGVPbkJsdXI6IHRydWUsXG5cdFx0XHRydWxlczoge1xuXHRcdFx0XHQvLyBBZGQgcnVsZSB0byB2YWxpZGF0ZSBBT0kgZm9ybSBpdGVtc1xuXHRcdFx0XHQvLyAoc2VlOiBodHRwczovL2RlbW9zLnRlbGVyaWsuY29tL2tlbmRvLXVpL3ZhbGlkYXRvci9jdXN0b20tdmFsaWRhdGlvbilcblx0XHRcdFx0YW9pOiBmdW5jdGlvbiAoaW5wdXQpIHtcblx0XHRcdFx0XHRpZiAoaW5wdXQuaXMoJ1tkYXRhLWFvaS1tc2ddJykgJiYgaW5wdXQudmFsKCkgIT0gJycpXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0aWYgKGlucHV0LnZhbCgpID09ICcwLDAsMCcpXG5cdFx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH1cblx0XHRcdH1cblx0XHR9KS5kYXRhKCdrZW5kb1ZhbGlkYXRvcicpO1xuXHR9XG5cblx0ZGVzdHJveUludGVyZmFjZSgpXG5cdHtcblx0XHQvLyBEZXN0cm95IGFsbCBLZW5kbyB3aWRnZXRzIGluIGZvcm1zXG5cdFx0a2VuZG8uZGVzdHJveSgkKGAjJHt0aGlzLl9tYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+IGRpdi50YWItcGFuZSA+IGZvcm1gKSk7XG5cblx0XHQvLyBSZW1vdmUgYWxsIHRhYnNcblx0XHQkKGAjJHt0aGlzLl9tYWluQ29udGFpbmVySWR9ID4gI3RhYnNgKS5lbXB0eSgpO1xuXG5cdFx0Ly8gUmVtb3ZlIGR5bmFtaWMgdGFiIHBhbmVzICh0YWIgcGFuZXMgY3JlYXRlZCBieSBJbnRlcmZhY2UgQnVpbGRlcilcblx0XHQkKGAjJHt0aGlzLl9tYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+IGRpdi50YWItcGFuZVtkYXRhLWR5bmFtaWM9XCJ0cnVlXCJdYCkucmVtb3ZlKCk7XG5cblx0XHQvLyBSZW1vdmUgZm9ybSBpbnNpZGUgc3RhdGljIHRhYiBwYW5lcyAocHJlZGVmaW5lZCB0YWIgcGFuZXMgaW4gaHRtbClcblx0XHQkKGAjJHt0aGlzLl9tYWluQ29udGFpbmVySWR9ID4gI3RhYlBhbmVscyA+IGRpdi50YWItcGFuZSA+IGZvcm1gKS5yZW1vdmUoKTtcblx0fVxuXG5cdGRpc2FibGVJbnRlcmZhY2UoZGlzYWJsZSlcblx0e1xuXHRcdC8vIEVuYWJsZS9kaXNhYmxlIGFsbCBjb25maWcgZm9ybSBpdGVtc1xuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gKltpZF49J2Zvcm0taXRlbS0nXWApLnByb3AoJ2VkaXRFbmFibGVkJywgIWRpc2FibGUpO1xuXHR9XG5cblx0X2J1aWxkU2VwYXJhdG9yKHNlcGFyYXRvcilcblx0e1xuXHRcdGlmIChzZXBhcmF0b3IudGV4dCA9PSBudWxsKVxuXHRcdFx0cmV0dXJuICQoYDxociBjbGFzcz1cImNvbmZpZy1mb3JtLXNlcGFyYXRvclwiPmApO1xuXG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuICQoYDxsYWJlbCBjbGFzcz1cImNvbmZpZy1mb3JtLXNlcGFyYXRvci1sYWJlbCBtYi0zXCI+JHtzZXBhcmF0b3IudGV4dH08L2xhYmVsPmApO1xuXHR9XG5cblx0Z2V0Q2hhbmdlZERhdGEoKVxuXHR7XG5cdFx0bGV0IGNoYW5nZXMgPSBuZXcgU0ZTMlguU0ZTQXJyYXkoKTtcblxuXHRcdGZvciAodmFyIGNwIG9mIHRoaXMuX2NvbmZpZ1BhcmFtcylcblx0XHR7XG5cdFx0XHRpZiAoY3AuaXNNb2RpZmllZClcblx0XHRcdFx0Y2hhbmdlcy5hZGRTRlNPYmplY3QoY3AudG9TZnNPYmplY3QoKSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNoYW5nZXM7XG5cdH1cblxuXHRyZXNldElzTW9kaWZpZWQoKVxuXHR7XG5cdFx0Zm9yIChsZXQgY3Agb2YgdGhpcy5fY29uZmlnUGFyYW1zKVxuXHRcdHtcblx0XHRcdGlmIChjcC5pc01vZGlmaWVkKVxuXHRcdFx0XHRjcC5yZXNldElzTW9kaWZpZWQoKTtcblx0XHR9XG5cdH1cblxuXHRjaGVja0lzVmFsaWQoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbGlkYXRvci52YWxpZGF0ZSgpO1xuXHR9XG5cblx0cmVzZXRWYWxpZGF0aW9uKClcblx0e1xuXHRcdHRoaXMuX3ZhbGlkYXRvci5oaWRlTWVzc2FnZXMoKTtcblxuXHRcdC8vIFRoZSBtZXRob2QgYWJvdmUgZG9lc24ndCByZW1vdmUgdGhlIGstaW52YWxpZCBjbGFzc2VzIGFuZCBhcmlhLWludmFsaWQ9XCJ0cnVlXCIgYXR0cmlidXRlcyBmcm9tIGlucHV0c1xuXHRcdC8vIExldCdzIGRvIGl0IG1hbnVhbGx5XG5cdFx0JChgIyR7dGhpcy5fbWFpbkNvbnRhaW5lcklkfSAuay1pbnZhbGlkYCkucmVtb3ZlQ2xhc3MoJ2staW52YWxpZCcpO1xuXHRcdCQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gW2FyaWEtaW52YWxpZD1cInRydWVcIl1gKS5yZW1vdmVBdHRyKCdhcmlhLWludmFsaWQnKTtcblx0fVxuXG5cdGdldENvbmZpZ0Zvcm1JdGVtKGNvbmZpZ1BhcmFtTmFtZSlcblx0e1xuXHRcdGxldCBmb3JtSXRlbSA9ICQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH1gKS5maW5kKGAjZm9ybS1pdGVtLSR7JC5lc2NhcGVTZWxlY3Rvcihjb25maWdQYXJhbU5hbWUpfWApO1xuXG5cdFx0aWYgKGZvcm1JdGVtLmxlbmd0aCA+IDApXG5cdFx0XHRyZXR1cm4gZm9ybUl0ZW1bMF07XG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIG51bGw7XG5cdH1cblxuXHRhY3RpdmF0ZUZpcnN0VGFiUGFuZWwoKVxuXHR7XG5cdFx0bGV0IGNvbmZpZ1BhcmFtID0gdGhpcy5fY29uZmlnUGFyYW1zWzBdO1xuXHRcdGNvbnN0IHRhYlBhbmVJZCA9IHRoaXMuVEFCX1BBTkVfUFJFRklYICsgY29uZmlnUGFyYW0uY2F0ZWdvcnlJZDtcblx0XHRsZXQgdGFiUGFuZSA9ICQoYCMke3RoaXMuX21haW5Db250YWluZXJJZH0gPiAjdGFiUGFuZWxzID4gIyR7dGFiUGFuZUlkfWApO1xuXHRcdHRhYlBhbmUuYWRkQ2xhc3MoJ3Nob3cgYWN0aXZlJyk7XG5cdH1cbn1cbiIsImV4cG9ydCBjbGFzcyBDb25maWd1cmF0aW9uUGFyYW1ldGVyXG57XG5cdHN0YXRpYyBmcm9tU2ZzT2JqZWN0KGVsZW1lbnQpXG5cdHtcblx0XHRsZXQgY3AgPSBuZXcgQ29uZmlndXJhdGlvblBhcmFtZXRlcigpO1xuXG5cdFx0Ly8gUGFyc2UgY29tbW9uIGRhdGFcblx0XHRjcC5uYW1lID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ25hbWUnKTtcblx0XHRjcC5sYWJlbCA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCdsYWJlbCcpO1xuXHRcdGNwLmNhdGVnb3J5ID0gZWxlbWVudC5nZXRVdGZTdHJpbmcoJ2NhdGVnb3J5Jyk7XG5cdFx0Y3AudG9vbHRpcCA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCd0b29sdGlwJyk7XG5cdFx0Y3AudHlwZSA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCd0eXBlJyk7XG5cdFx0Y3AudmFsdWUgPSBlbGVtZW50LmdldCgndmFsdWUnKTtcblx0XHRjcC52YWxpZGF0b3IgPSBlbGVtZW50LmdldFV0ZlN0cmluZygndmFsaWRhdG9yJyk7XG5cdFx0Y3AuZWRpdGFibGUgPSAoZWxlbWVudC5jb250YWluc0tleSgnZWRpdCcpID8gZWxlbWVudC5nZXRCb29sKCdlZGl0JykgOiB0cnVlKTtcblx0XHRjcC50cmlnZ2VyID0gKGVsZW1lbnQuY29udGFpbnNLZXkoJ3RyaWdnZXInKSA/IGVsZW1lbnQuZ2V0Qm9vbCgndHJpZ2dlcicpIDogZmFsc2UpO1xuXHRcdGNwLnRyaWdnZXJEYXRhID0gZWxlbWVudC5nZXRTRlNBcnJheSgndHJpZ2dlckRhdGEnKTtcblx0XHRjcC5jbGllbnRPbmx5ID0gKGVsZW1lbnQuY29udGFpbnNLZXkoJ2NsaWVudE9ubHknKSA/IGVsZW1lbnQuZ2V0Qm9vbCgnY2xpZW50T25seScpIDogZmFsc2UpO1xuXHRcdGNwLmRhdGFQcm92aWRlciA9IGVsZW1lbnQuZ2V0VXRmU3RyaW5nKCdkYXRhUHJvdmlkZXInKTtcblxuXHRcdC8vIFBhcnNlIGNvbXBvbmVudCBzcGVjaWZpYyBhdHRyaWJ1dGVzXG5cdFx0bGV0IHRtcEF0dHJpYnV0ZXMgPSBlbGVtZW50LmdldFNGU09iamVjdCgnYXR0cmlidXRlcycpO1xuXHRcdGlmICh0bXBBdHRyaWJ1dGVzICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0bGV0IGF0dHJpYnV0ZXMgPSB7fTtcblxuXHRcdFx0bGV0IGtleXMgPSB0bXBBdHRyaWJ1dGVzLmdldEtleXNBcnJheSgpO1xuXHRcdFx0Zm9yIChsZXQga2V5IG9mIGtleXMpXG5cdFx0XHRcdGF0dHJpYnV0ZXNba2V5XSA9IHRtcEF0dHJpYnV0ZXMuZ2V0KGtleSk7XG5cblx0XHRcdGNwLmF0dHJpYnV0ZXMgPSBhdHRyaWJ1dGVzO1xuXHRcdH1cblxuXHRcdC8vIFBhcnNlIHNlcGFyYXRvciBzZXR0aW5nc1xuXHRcdGxldCB0bXBTZXBhcmF0b3IgPSBlbGVtZW50LmdldFNGU09iamVjdCgnc2VwYXJhdG9yJyk7XG5cdFx0aWYgKHRtcFNlcGFyYXRvciAhPSBudWxsKVxuXHRcdHtcblx0XHRcdGxldCBzZXBhcmF0b3IgPSB7fTtcblxuXHRcdFx0bGV0IGtleXMxID0gdG1wU2VwYXJhdG9yLmdldEtleXNBcnJheSgpO1xuXHRcdFx0Zm9yIChsZXQga2V5MSBvZiBrZXlzMSlcblx0XHRcdFx0c2VwYXJhdG9yW2tleTFdID0gdG1wU2VwYXJhdG9yLmdldChrZXkxKTtcblxuXHRcdFx0Y3Auc2VwYXJhdG9yID0gc2VwYXJhdG9yO1xuXHRcdH1cblxuXHRcdC8vIFBhcnNlIGRlZmF1bHQgbGlzdCBpdGVtXG5cdFx0bGV0IHRtcERlZmF1bHRMaXN0SXRlbSA9IGVsZW1lbnQuZ2V0U0ZTQXJyYXkoJ2RlZmF1bHRMaXN0SXRlbScpO1xuXHRcdGlmICh0bXBEZWZhdWx0TGlzdEl0ZW0gIT0gbnVsbCAmJiB0bXBEZWZhdWx0TGlzdEl0ZW0uc2l6ZSgpID4gMClcblx0XHR7XG5cdFx0XHRsZXQgZGVmYXVsdExpc3RJdGVtID0gW107XG5cblx0XHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdG1wRGVmYXVsdExpc3RJdGVtLnNpemUoKTsgaSsrKVxuXHRcdFx0XHRkZWZhdWx0TGlzdEl0ZW0ucHVzaChDb25maWd1cmF0aW9uUGFyYW1ldGVyLmZyb21TZnNPYmplY3QodG1wRGVmYXVsdExpc3RJdGVtLmdldFNGU09iamVjdChpKSkpO1xuXG5cdFx0XHRjcC5kZWZhdWx0TGlzdEl0ZW0gPSBkZWZhdWx0TGlzdEl0ZW07XG5cblx0XHRcdC8vIFBhcnNlIGxpc3QgdmFsdWVzXG5cdFx0XHRsZXQgbGlzdFZhbHVlcyA9IFtdO1xuXG5cdFx0XHRsZXQgdG1wTGlzdFZhbHVlcyA9IGVsZW1lbnQuZ2V0U0ZTQXJyYXkoJ2xpc3RWYWx1ZXMnKTtcblx0XHRcdGlmICh0bXBMaXN0VmFsdWVzICE9IG51bGwgJiYgdG1wTGlzdFZhbHVlcy5zaXplKCkgPiAwKVxuXHRcdFx0e1xuXHRcdFx0XHRmb3IgKGxldCB2ID0gMDsgdiA8IHRtcExpc3RWYWx1ZXMuc2l6ZSgpOyB2KyspXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRsZXQgbGlzdFZhbHVlT2JqID0gdG1wTGlzdFZhbHVlcy5nZXRTRlNPYmplY3Qodik7XG5cdFx0XHRcdFx0bGV0IG9iaiA9IHt9O1xuXG5cdFx0XHRcdFx0bGV0IGtleXMyID0gbGlzdFZhbHVlT2JqLmdldEtleXNBcnJheSgpO1xuXHRcdFx0XHRcdGZvciAobGV0IGtleTIgb2Yga2V5czIpXG5cdFx0XHRcdFx0XHRvYmpba2V5Ml0gPSBsaXN0VmFsdWVPYmouZ2V0KGtleTIpO1xuXG5cdFx0XHRcdFx0bGlzdFZhbHVlcy5wdXNoKG9iaik7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Y3AubGlzdFZhbHVlcyA9IGxpc3RWYWx1ZXM7XG5cblx0XHRcdC8vIElmIHdlIGhhdmUgYSBsaXN0LCBvbiB0aGUgc2VydmVyLXNpZGUgaXRlbXMgY291bGQgYmUgcmVwcmVzZW50ZWQgYnkgYSBjbGFzc1xuXHRcdFx0Y3AuY2xhenogPSBlbGVtZW50LmdldFV0ZlN0cmluZygnY2xhenonKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gY3A7XG5cdH1cblxuXHRjb25zdHJ1Y3RvcigpXG5cdHtcblx0XHQvKiBDT05TVEFOVFMgKi9cblx0XHR0aGlzLkRFRkFVTFRfQ0FURUdPUllfTkFNRSA9ICdHZW5lcmFsJztcblx0XHR0aGlzLkRFRkFVTFRfQ0FURUdPUllfSUQgPSAnZ2VuZXJhbCc7XG5cblx0XHQvKiBQVUJMSUMgVkFSUyAqL1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cdFx0dGhpcy5sYWJlbCA9ICcnO1xuXHRcdHRoaXMudG9vbHRpcCA9ICcnO1xuXHRcdHRoaXMudHlwZSA9IG51bGw7XG5cdFx0dGhpcy50cmlnZ2VyID0gZmFsc2U7XG5cdFx0dGhpcy50cmlnZ2VyRGF0YSA9IG51bGw7XG5cdFx0dGhpcy5jbGllbnRPbmx5ID0gZmFsc2U7XG5cdFx0dGhpcy5lZGl0YWJsZSA9IHRydWU7XG5cdFx0dGhpcy5hdHRyaWJ1dGVzID0gbnVsbDtcblx0XHR0aGlzLmRhdGFQcm92aWRlciA9IG51bGw7XG5cblx0XHR0aGlzLnNlcGFyYXRvciA9IG51bGw7XHRcdFx0Ly8gUGFyYW1ldGVyIHVzZWQgdG8gY3JlYXRlIGEgc2VwYXJhdG9yIGJlZm9yZSBvciBhZnRlciB0aGUgY29uZmlnIHBhcmFtZXRlclxuXHRcdHRoaXMuZGVmYXVsdExpc3RJdGVtID0gbnVsbDtcdFx0Ly8gTGlzdCBvZiBzdWItQ29uZmlndXJhdGlvblBhcmFtZXRlcnMsIGVhY2ggY29udGFpbmluZyB0aGUgZGVmYXVsdCB2YWx1ZXNcblx0XHR0aGlzLmNsYXp6ID0gbnVsbDtcdFx0XHRcdC8vIE5hbWUgb2YgdGhlIGNsYXNzIHJlcHJlc2VudGluZyB0aGUgbGlzdCBpdGVtIChub3QgdXNlZCBpbiBjYXNlIG9mIHByaW1pdGV2ZSBkYXRhIHR5cGVzKVxuXG5cdFx0LyogUFJJVkFURSBWQVJTICovXG5cblx0XHR0aGlzLl9jYXRlZ29yeSA9IHRoaXMuREVGQVVMVF9DQVRFR09SWV9OQU1FO1xuXHRcdHRoaXMuX2NhdGVnb3J5SWQgPSB0aGlzLkRFRkFVTFRfQ0FURUdPUllfSUQ7XG5cdFx0dGhpcy5fdmFsdWUgPSBudWxsO1xuXHRcdHRoaXMuX2luaXRpYWxWYWx1ZSA9IG51bGw7XHRcdC8vIFNhdmUgdGhlIGluaXRpYWwgdmFsdWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gcGFyYW1ldGVyLCB0byBjaGVjayBpZiB0aGUgdmFsdWUgd2FzIG1vZGlmaWVkXG5cdFx0dGhpcy5fdmFsaWRhdG9yID0gbnVsbDtcblxuXHRcdHRoaXMuX2xpc3RJdGVtcyA9IFtdO1x0XHRcdC8vIEFycmF5IG9mIGFycmF5cyBvZiBDb25maWd1cmF0aW9uUGFyYW1ldGVyc1xuXHRcdHRoaXMuX2xpc3RJdGVtc0NoYW5nZWQgPSBmYWxzZTtcdC8vIEZsYWcgdG8gYmUgc2V0IGluIGNhc2UgYSBsaXN0IGl0ZW0gaXMgYWRkZWQgb3IgcmVtb3ZlZFxuXHR9XG5cblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0Ly8gR0VUVEVSUyAvIFNFVFRFUlNcblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRzZXQgY2F0ZWdvcnkodmFsKVxuXHR7XG5cdFx0aWYgKHZhbClcblx0XHR7XG5cdFx0XHR0aGlzLl9jYXRlZ29yeSA9IHZhbDtcblx0XHRcdHRoaXMuX3NldElkRnJvbUNhdGVnb3J5TmFtZSh0aGlzLl9jYXRlZ29yeSk7XG5cdFx0fVxuXHR9XG5cblx0Z2V0IGNhdGVnb3J5KClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9jYXRlZ29yeTtcblx0fVxuXG5cdHNldCB2YWx1ZSh2YWwpXG5cdHtcblx0XHRpZiAodGhpcy5fdmFsdWUgIT0gdmFsKVxuXHRcdHtcblx0XHRcdC8vIElmIHZhbHVlIGlzIG51bGwsIHRoZW4gd2UgYXJlIHNldHRpbmcgdGhpcyBmb3IgdGhlIGZpcnN0IHRpbWUgYW5kXG5cdFx0XHQvLyB3ZSB3YW50IHRvIHNhdmUgdGhlIGluaXRpYWwgdmFsdWUsIHRvIGNoZWNrIGxhdGVyIGlmIGl0IGhhcyBiZWVuIG1vZGlmaWVkXG5cdFx0XHRpZiAodGhpcy5fdmFsdWUgPT0gbnVsbClcblx0XHRcdFx0dGhpcy5faW5pdGlhbFZhbHVlID0gdmFsO1xuXG5cdFx0XHR0aGlzLl92YWx1ZSA9IHZhbDtcblx0XHR9XG5cdH1cblxuXHRnZXQgdmFsdWUoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX3ZhbHVlO1xuXHR9XG5cblx0c2V0IHZhbGlkYXRvcih2YWwpXG5cdHtcblx0XHRpZiAodmFsKVxuXHRcdFx0dGhpcy5fdmFsaWRhdG9yID0gdmFsO1xuXHR9XG5cblx0Z2V0IHZhbGlkYXRvcigpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fdmFsaWRhdG9yO1xuXHR9XG5cblx0LyoqXG5cdCAqIEFuIGFycmF5IG9mIG9iamVjdHM7IGVhY2ggb2JqZWN0IGNvbnRhaW5zIHRoZSBuYW1lLXZhbHVlIHBhaXJzIHVzZWQgdG9cblx0ICogcG9wdWxhdGUgdGhlIGxpc3Qgb2Ygc3ViLWNvbmZpZ3VyYXRpb24gcGFyYW1ldGVycyBhcnJheXMsIGJhc2VkIG9uIGRlZmF1bHRMaXN0SXRlbS5cblx0ICovXG5cdHNldCBsaXN0VmFsdWVzKGFycilcblx0e1xuXHRcdHRoaXMuX3NldFN1YkNvbmZpZ3VyYXRpb25QYXJhbXMoYXJyKTtcblx0fVxuXG5cdGdldCBsaXN0VmFsdWVzKClcblx0e1xuXHRcdHJldHVybiB0aGlzLl9nZXRTdWJDb25maWd1cmF0aW9uUGFyYW1zVmFsdWVzKCk7XG5cdH1cblxuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvLyBHRVRURVJTIE9OTFlcblx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRnZXQgaXNNb2RpZmllZCgpXG5cdHtcblx0XHRsZXQgX2lzTW9kaWZpZWQgPSBmYWxzZTtcblxuXHRcdC8vIElmIHRoZSBwYXJhbWV0ZXIgaXMgdXNlZCBvbiB0aGUgY2xpZW50IG9ubHkgKGZvciBleGFtcGxlIGluIGEgY3VzdG9tIHRyaWdnZXIpXG5cdFx0Ly8gdGhlbiB3ZSBuZXZlciBoYXZlIHRvIGNvbnNpZGVyIGl0IGFzIG1vZGlmaWVkLCB0byBwcmV2ZW50IGl0IGJlaW5nIHNlbnQgdG8gdGhlIHNlcnZlclxuXHRcdGlmICghdGhpcy5jbGllbnRPbmx5KVxuXHRcdHtcblx0XHRcdGlmICh0aGlzLl92YWx1ZSAhPSB0aGlzLl9pbml0aWFsVmFsdWUgfHwgdGhpcy5fbGlzdEl0ZW1zQ2hhbmdlZClcblx0XHRcdFx0X2lzTW9kaWZpZWQgPSB0cnVlO1xuXHRcdFx0ZWxzZVxuXHRcdFx0e1xuXHRcdFx0XHQvLyBDaGVjayBzdWIgcGFyYW1ldGVyc1xuXHRcdFx0XHRvdXRlckxvb3A6IGZvciAobGV0IGxpc3RJdGVtIG9mIHRoaXMuX2xpc3RJdGVtcylcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGZvciAobGV0IHN1YkNQIG9mIGxpc3RJdGVtKVxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdGlmIChzdWJDUC5pc01vZGlmaWVkKVxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHRfaXNNb2RpZmllZCA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdGJyZWFrIG91dGVyTG9vcDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gX2lzTW9kaWZpZWQ7XG5cdH1cblxuXHRnZXQgY2F0ZWdvcnlJZCgpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5fY2F0ZWdvcnlJZDtcblx0fVxuXG5cdGdldCBsaXN0SXRlbXMoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXMuX2xpc3RJdGVtcztcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFBVQkxJQyBNRVRIT0RTXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0LyoqXG5cdCAqIFJldHVybiBhIGNsb25lIG9mIHRoaXMgQ29uZmlndXJhdGlvblBhcmFtZXRlci5cblx0ICovXG5cdGNsb25lKGNsb25lVmFsdWUgPSBmYWxzZSlcblx0e1xuXHRcdGxldCBjcCA9IG5ldyBDb25maWd1cmF0aW9uUGFyYW1ldGVyKCk7XG5cdFx0Y3AubmFtZSA9IHRoaXMubmFtZTtcblx0XHRjcC5sYWJlbCA9IHRoaXMubGFiZWw7XG5cdFx0Y3AuY2F0ZWdvcnkgPSB0aGlzLmNhdGVnb3J5O1xuXHRcdGNwLnRvb2x0aXAgPSB0aGlzLnRvb2x0aXA7XG5cdFx0Y3AudHlwZSA9IHRoaXMudHlwZTtcblx0XHRjcC52YWxpZGF0b3IgPSB0aGlzLnZhbGlkYXRvcjtcblx0XHRjcC50cmlnZ2VyID0gdGhpcy50cmlnZ2VyO1xuXHRcdGNwLnRyaWdnZXJEYXRhID0gKHRoaXMudHJpZ2dlckRhdGEgIT0gbnVsbCA/IFNGUzJYLlNGU0FycmF5Lm5ld0Zyb21CaW5hcnlEYXRhKHRoaXMudHJpZ2dlckRhdGEudG9CaW5hcnkoKSkgOiBudWxsKTtcblx0XHRjcC5jbGllbnRPbmx5ID0gdGhpcy5jbGllbnRPbmx5O1xuXHRcdGNwLmRhdGFQcm92aWRlciA9IHRoaXMuZGF0YVByb3ZpZGVyO1xuXG5cdFx0aWYgKGNsb25lVmFsdWUpXG5cdFx0XHRjcC52YWx1ZSA9IHRoaXMudmFsdWU7XG5cblx0XHRpZiAodGhpcy5hdHRyaWJ1dGVzICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0Y3AuYXR0cmlidXRlcyA9IG5ldyBPYmplY3QoKTtcblx0XHRcdGZvciAobGV0IHMxIGluIHRoaXMuYXR0cmlidXRlcylcblx0XHRcdFx0Y3AuYXR0cmlidXRlc1tzMV0gPSB0aGlzLmF0dHJpYnV0ZXNbczFdO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLnNlcGFyYXRvciAhPSBudWxsKVxuXHRcdHtcblx0XHRcdGNwLnNlcGFyYXRvciA9IG5ldyBPYmplY3QoKVxuXHRcdFx0Zm9yIChsZXQgczIgaW4gdGhpcy5zZXBhcmF0b3IpXG5cdFx0XHRcdGNwLnNlcGFyYXRvcltzMl0gPSB0aGlzLnNlcGFyYXRvcltzMl07XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuZGVmYXVsdExpc3RJdGVtICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0bGV0IGNsb25lZERlZmF1bHRMaXN0SXRlbXMgPSBbXTtcblxuXHRcdFx0Zm9yIChsZXQgc3ViQ1Agb2YgdGhpcy5kZWZhdWx0TGlzdEl0ZW0pXG5cdFx0XHRcdGNsb25lZERlZmF1bHRMaXN0SXRlbXMucHVzaChzdWJDUC5jbG9uZShjbG9uZVZhbHVlKSk7XG5cblx0XHRcdGNwLmRlZmF1bHRMaXN0SXRlbSA9IGNsb25lZERlZmF1bHRMaXN0SXRlbXM7XG5cdFx0fVxuXG5cdFx0Y3AubGlzdFZhbHVlcyA9IHRoaXMubGlzdFZhbHVlczsgLy8gTm8gbmVlZCB0byBjbG9uZSB0aGlzLCBhcyB0aGUgbGlzdFZhbHVlcyBzZXR0ZXIgYWxyZWFkeSBkb2VzIGl0XG5cdFx0Y3AuY2xhenogPSB0aGlzLmNsYXp6O1xuXG5cdFx0cmV0dXJuIGNwO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJlc2V0IGluaXRpYWwgdmFsdWUgYnkgY29weWluZyB0aGUgY3VycmVudCB2YWx1ZS5cblx0ICovXG5cdHJlc2V0SXNNb2RpZmllZCgpXG5cdHtcblx0XHR0aGlzLl9pbml0aWFsVmFsdWUgPSB0aGlzLl92YWx1ZTtcblxuXHRcdC8vIFJlc2V0IHN1Yi1wYXJhbWV0ZXJzXG5cdFx0aWYgKHRoaXMuX2xpc3RJdGVtcyAhPSBudWxsKVxuXHRcdHtcblx0XHRcdGZvciAobGV0IGxpc3RJdGVtIG9mIHRoaXMuX2xpc3RJdGVtcylcblx0XHRcdHtcblx0XHRcdFx0Zm9yIChsZXQgc3ViQ1Agb2YgbGlzdEl0ZW0pXG5cdFx0XHRcdFx0c3ViQ1AucmVzZXRJc01vZGlmaWVkKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5fbGlzdEl0ZW1zQ2hhbmdlZCA9IGZhbHNlO1xuXHR9XG5cblx0YWRkTGlzdEl0ZW0obmV3TGlzdEl0ZW0pXG5cdHtcblx0XHR0aGlzLl9saXN0SXRlbXMucHVzaChuZXdMaXN0SXRlbSk7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zQ2hhbmdlZCA9IHRydWU7XG5cdH1cblxuXHR1cGRhdGVMaXN0SXRlbShsaXN0SXRlbSwgaXRlbUluZGV4KVxuXHR7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zW2l0ZW1JbmRleF0gPSBsaXN0SXRlbTtcblx0XHR0aGlzLl9saXN0SXRlbXNDaGFuZ2VkID0gdHJ1ZTtcblx0fVxuXG5cdHJlbW92ZUxpc3RJdGVtKGl0ZW1JbmRleClcblx0e1xuXHRcdHRoaXMuX2xpc3RJdGVtcy5zcGxpY2UoaXRlbUluZGV4LCAxKTtcblx0XHR0aGlzLl9saXN0SXRlbXNDaGFuZ2VkID0gdHJ1ZTtcblx0fVxuXG5cdHRvU2ZzT2JqZWN0KClcblx0e1xuXHRcdGxldCBvYmogPSBuZXcgU0ZTMlguU0ZTT2JqZWN0KCk7XG5cblx0XHQvLyBTZXQgY2hhbmdlZCBzZXR0aW5nIG5hbWVcblx0XHRvYmoucHV0VXRmU3RyaW5nKCduYW1lJywgdGhpcy5uYW1lKTtcblxuXHRcdC8vIFNldCBjaGFuZ2VkIHNldHRpbmcgY2xhc3MsIGlmIGFueVxuXHRcdGlmICh0aGlzLmNsYXp6ICE9IG51bGwpXG5cdFx0XHRvYmoucHV0VXRmU3RyaW5nKCdjbGF6eicsIHRoaXMuY2xhenopO1xuXG5cdFx0aWYgKHRoaXMudmFsdWUgIT0gbnVsbClcblx0XHR7XG5cdFx0XHQvLyBTZXQgY2hhbmdlZCBzZXR0aW5nIHZhbHVlXG5cdFx0XHRpZiAodHlwZW9mIHRoaXMudmFsdWUgPT09ICdib29sZWFuJylcblx0XHRcdFx0b2JqLnB1dEJvb2woJ3ZhbHVlJywgdGhpcy52YWx1ZSk7XG5cdFx0XHRlbHNlIGlmICh0eXBlb2YgdGhpcy52YWx1ZSA9PT0gJ251bWJlcicpXG5cdFx0XHRcdG9iai5wdXRJbnQoJ3ZhbHVlJywgdGhpcy52YWx1ZSk7XG5cdFx0XHRlbHNlXG5cdFx0XHRcdG9iai5wdXRUZXh0KCd2YWx1ZScsIHRoaXMudmFsdWUpO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0Ly8gU2V0IGNoYW5nZWQgc2V0dGluZyBsaXN0IG9mIHZhbHVlc1xuXG5cdFx0XHRsZXQgbGlzdEl0ZW1zID0gbmV3IFNGUzJYLlNGU0FycmF5KCk7XG5cblx0XHRcdGZvciAobGV0IGEgb2YgdGhpcy5fbGlzdEl0ZW1zKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoYS5sZW5ndGggPT0gMSkgLy8gV2UgaGF2ZSBqdXN0IG9uZSBzdWIgY29uZmlnIHBhcmFtOyBubyBuZWVkIHRvIHBhcnNlIGl0IGNvbXBsaXRlbHlcblx0XHRcdFx0e1xuXHRcdFx0XHRcdC8vIFNpbXBsZSBsaXN0XG5cdFx0XHRcdFx0bGV0IHRlbXBPYmogPSBhWzBdLnRvU2ZzT2JqZWN0KCk7XG5cdFx0XHRcdFx0bGV0IHdhID0gdGVtcE9iai5nZXRXcmFwcGVkSXRlbSgndmFsdWUnKTtcblx0XHRcdFx0XHRsaXN0SXRlbXMuYWRkKHdhLnZhbHVlLCB3YS50eXBlKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlXG5cdFx0XHRcdHtcblx0XHRcdFx0XHQvLyBDb21wbGV4IGxpc3RcblxuXHRcdFx0XHRcdGxldCB2YWx1ZXMgPSBuZXcgU0ZTMlguU0ZTQXJyYXkoKTtcblxuXHRcdFx0XHRcdGZvciAobGV0IHN1YkNwIG9mIGEpXG5cdFx0XHRcdFx0XHR2YWx1ZXMuYWRkU0ZTT2JqZWN0KHN1YkNwLnRvU2ZzT2JqZWN0KCkpO1xuXG5cdFx0XHRcdFx0bGlzdEl0ZW1zLmFkZFNGU0FycmF5KHZhbHVlcyk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0b2JqLnB1dFNGU0FycmF5KCd2YWx1ZScsIGxpc3RJdGVtcyk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG9iajtcblx0fVxuXG5cdC8qKlxuXHQgKiBSZXR1cm4gYSBkZXNjcmlwdGlvbiBvZiB0aGUgQ29uZmlndXJhdGlvblBhcmFtZXRlciBpbnN0YW5jZS5cblx0ICovXG5cdHRvU3RyaW5nKClcblx0e1xuXHRcdGxldCBzID0gYGA7XG5cdFx0cyArPSBgQ29uZmlndXJhdGlvbiBwYXJhbWV0ZXI6ICR7dGhpcy5uYW1lfVxcbmA7XG5cdFx0cyArPSBgXFx0dHlwZTogJHt0aGlzLnR5cGV9XFxuYDtcblx0XHRzICs9IGBcXHRsYWJlbDogJHt0aGlzLmxhYmVsfVxcbmA7XG5cdFx0cyArPSBgXFx0Y2F0ZWdvcnkgbmFtZTogJHt0aGlzLmNhdGVnb3J5fVxcbmA7XG5cdFx0cyArPSBgXFx0Y2F0ZWdvcnkgaWQ6ICR7dGhpcy5jYXRlZ29yeUlkfVxcbmA7XG5cdFx0cyArPSBgXFx0dG9vbHRpcDogJHt0aGlzLnRvb2x0aXB9XFxuYDtcblx0XHRzICs9IGBcXHR2YWx1ZTogJHt0aGlzLnZhbHVlfVxcbmA7XG5cdFx0cyArPSBgXFx0dHJpZ2dlcjogJHt0aGlzLnRyaWdnZXJ9XFxuYDtcblx0XHRzICs9IGBcXHR0cmlnZ2VyIGRhdGE6ICR7dGhpcy50cmlnZ2VyRGF0YX1cXG5gO1xuXHRcdHMgKz0gYFxcdGNsaWVudCBvbmx5OiAke3RoaXMuY2xpZW50T25seX1cXG5gO1xuXHRcdHMgKz0gYFxcdHZhbGlkYXRvcjogJHt0aGlzLnZhbGlkYXRvcn1cXG5gO1xuXHRcdHMgKz0gYFxcdGlzIG1vZGlmaWVkOiAke3RoaXMuaXNNb2RpZmllZH1cXG5gO1xuXG5cdFx0aWYgKHRoaXMuYXR0cmlidXRlcyAhPSBudWxsKVxuXHRcdHtcblx0XHRcdHMgKz0gYFxcdGNvbXBvbmVudCBhdHRyaWJ1dGVzOlxcbmA7XG5cblx0XHRcdGZvciAobGV0IHMxIGluIHRoaXMuYXR0cmlidXRlcylcblx0XHRcdFx0cyArPSBgXFx0XFx0JHtzMX0gLS0+ICR7dGhpcy5hdHRyaWJ1dGVzW3MxXX1cXG5gO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLmRhdGFQcm92aWRlciAhPSBudWxsKVxuXHRcdFx0cyArPSBgXFx0ZGF0YSBwcm92aWRlcjogJHt0aGlzLmRhdGFQcm92aWRlcn1cXG5gO1xuXG5cdFx0aWYgKHRoaXMuc2VwYXJhdG9yICE9IG51bGwpXG5cdFx0e1xuXHRcdFx0cyArPSBgXFx0c2VwYXJhdG9yOlxcbmA7XG5cblx0XHRcdGZvciAobGV0IHMyIGluIHRoaXMuc2VwYXJhdG9yKVxuXHRcdFx0XHRzICs9IGBcXHRcXHQke3MyfSAtLT4gJHt0aGlzLnNlcGFyYXRvcltzMl19XFxuYDtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5fbGlzdEl0ZW1zICE9IG51bGwgJiYgdGhpcy5fbGlzdEl0ZW1zLmxlbmd0aCA+IDApXG5cdFx0e1xuXHRcdFx0cyArPSBgXFx0IyBsaXN0IGl0ZW1zOiAke3RoaXMuX2xpc3RJdGVtcy5sZW5ndGh9XFxuYDtcblxuXHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLl9saXN0SXRlbXMubGVuZ3RoOyBpKyspXG5cdFx0XHR7XG5cdFx0XHRcdHMgKz0gYFxcdGxpc3QgaXRlbSAke2l9IHN1Yi1wYXJhbWV0ZXJzOlxcbmA7XG5cdFx0XHRcdGZvciAobGV0IGUgPSAwOyBlIDwgdGhpcy5fbGlzdEl0ZW1zW2ldLmxlbmd0aDsgZSsrKVxuXHRcdFx0XHRcdHMgKz0gYFxcdFxcdCR7dGhpcy5fbGlzdEl0ZW1zW2ldW2VdLnRvQ29tcGFjdFN0cmluZygpfVxcbmA7XG5cdFx0XHR9XG5cblx0XHRcdHMgKz0gYFxcdGNsYXNzIG5hbWU6ICR7dGhpcy5jbGF6en1cXG5gO1xuXHRcdH1cblxuXHRcdHJldHVybiBzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybiBhIGNvbXBhY3QgZGVzY3JpcHRpb24gb2YgdGhlIENvbmZpZ3VyYXRpb25QYXJhbWV0ZXIgaW5zdGFuY2UuXG5cdCAqL1xuXHR0b0NvbXBhY3RTdHJpbmcoKVxuXHR7XG5cdFx0cmV0dXJuIGBDb25maWd1cmF0aW9uIHBhcmFtZXRlciAnJHt0aGlzLm5hbWV9JzogJHt0aGlzLnZhbHVlfSAke3RoaXMuaXNNb2RpZmllZCA/ICdbWF0nIDogJ1sgXSd9YDtcblx0fVxuXG5cdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdC8vIFBSSVZBVEUgTUVUSE9EU1xuXHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdC8qKlxuXHQgKiBSZXRyaWV2ZSB0aGUgY2F0ZWdvcnkgaWQgZm9ybSB0aGUgY2F0ZWdvcnkgbmFtZS5cblx0ICogU3BhY2VzIGFuZCBpbnZhbGlkIGNoYXJhY3RlcnMgYXJlIHJlbW92ZWQ7IHdvcmRzIGFyZSBzZXBhcmF0ZWQgdXNpbmcgY2FwaXRhbHMuXG5cdCAqL1xuXHRfc2V0SWRGcm9tQ2F0ZWdvcnlOYW1lKGNhdGVnb3J5TmFtZSlcblx0e1xuXHRcdHRoaXMuX2NhdGVnb3J5SWQgPSBjYXRlZ29yeU5hbWU7XG5cblx0XHQvLyBTdHJpcCBpbnZhbGlkIGNoYXJhY3RlcnNcblx0XHR2YXIgcGF0dGVybiA9IC9bXjAtOWEtekEtWl0vZztcblx0XHR0aGlzLl9jYXRlZ29yeUlkID0gdGhpcy5fY2F0ZWdvcnlJZC5yZXBsYWNlKHBhdHRlcm4sICcgJyk7XG5cblx0XHQvLyBDYXBpdGFsaXplIHdvcmRzXG5cdFx0dmFyIHdvcmRzID0gdGhpcy5fY2F0ZWdvcnlJZC5zcGxpdCgnICcpO1xuXHRcdHRoaXMuX2NhdGVnb3J5SWQgPSAnJztcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgd29yZHMubGVuZ3RoOyBpKyspXG5cdFx0e1xuXHRcdFx0bGV0IHdvcmQgPSB3b3Jkc1tpXTtcblx0XHRcdGlmICh3b3JkLmxlbmd0aCA+IDApXG5cdFx0XHRcdHRoaXMuX2NhdGVnb3J5SWQgKz0gKGkgPiAwID8gd29yZC5zdWJzdHIoMCwxKS50b1VwcGVyQ2FzZSgpIDogd29yZC5zdWJzdHIoMCwxKS50b0xvd2VyQ2FzZSgpKSArICh3b3JkLmxlbmd0aCA+IDEgPyB3b3JkLnN1YnN0cigxKSA6IFwiXCIpO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLl9jYXRlZ29yeUlkLmxlbmd0aCA9PSAwKVxuXHRcdFx0dGhpcy5fY2F0ZWdvcnlJZCA9IHRoaXMuREVGQVVMVF9DQVRFR09SWV9JRDtcblx0fVxuXG5cdF9zZXRTdWJDb25maWd1cmF0aW9uUGFyYW1zKF9saXN0VmFsdWVzKVxuXHR7XG5cdFx0dGhpcy5fbGlzdEl0ZW1zID0gW107XG5cblx0XHRmb3IgKGxldCBvYmogb2YgX2xpc3RWYWx1ZXMpXG5cdFx0e1xuXHRcdFx0bGV0IGxpc3RJdGVtID0gW107XG5cblx0XHRcdGZvciAobGV0IGRlZmF1bHRDUCBvZiB0aGlzLmRlZmF1bHRMaXN0SXRlbSlcblx0XHRcdHtcblx0XHRcdFx0bGV0IHN1YkNQID0gZGVmYXVsdENQLmNsb25lKGZhbHNlKTtcblx0XHRcdFx0c3ViQ1AudmFsdWUgPSBvYmpbc3ViQ1AubmFtZV07XG5cblx0XHRcdFx0bGlzdEl0ZW0ucHVzaChzdWJDUCk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2xpc3RJdGVtcy5wdXNoKGxpc3RJdGVtKTtcblx0XHR9XG5cdH1cblxuXHRfZ2V0U3ViQ29uZmlndXJhdGlvblBhcmFtc1ZhbHVlcygpXG5cdHtcblx0XHRsZXQgX2xpc3RWYWx1ZXMgPSBbXTtcblxuXHRcdGZvciAobGV0IGxpc3RJdGVtIG9mIHRoaXMuX2xpc3RJdGVtcylcblx0XHR7XG5cdFx0XHRsZXQgb2JqID0ge307XG5cblx0XHRcdGZvciAobGV0IHN1YkNQIG9mIGxpc3RJdGVtKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoc3ViQ1AudmFsdWUgIT0gbnVsbClcblx0XHRcdFx0XHRvYmpbc3ViQ1AubmFtZV0gPSBzdWJDUC52YWx1ZTtcblx0XHRcdH1cblxuXHRcdFx0X2xpc3RWYWx1ZXMucHVzaChvYmopO1xuXHRcdH1cblxuXHRcdHJldHVybiBfbGlzdFZhbHVlcztcblx0fVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDNUdBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDeEhBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQ3pMQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUN4T0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7OztBQzNXQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUMzQkE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUMvR0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDekZBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDN0VBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7QUM3RUE7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDN0pBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUNoREE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7O0FDMVFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBIiwic291cmNlUm9vdCI6IiJ9