@geoit/ui 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/AGENTS.md +12 -8
  2. package/README.md +49 -62
  3. package/ai/AGENTS.md +38 -28
  4. package/ai/README.md +35 -1
  5. package/ai/catalog.json +2796 -288
  6. package/ai/components/geo-alert.md +3 -3
  7. package/ai/components/geo-back-button.md +2 -2
  8. package/ai/components/geo-breadcrumb.md +1 -1
  9. package/ai/components/geo-button.md +3 -3
  10. package/ai/components/geo-chart.md +103 -0
  11. package/ai/components/geo-checkbox.md +4 -6
  12. package/ai/components/geo-column-picker.md +3 -3
  13. package/ai/components/geo-confirm-modal.md +4 -5
  14. package/ai/components/geo-dashboard.md +91 -0
  15. package/ai/components/geo-date-picker.md +5 -3
  16. package/ai/components/geo-date-range-picker.md +5 -3
  17. package/ai/components/geo-empty-state.md +75 -0
  18. package/ai/components/geo-feedback-form.md +97 -0
  19. package/ai/components/geo-file-picker.md +4 -2
  20. package/ai/components/geo-forgot-password.md +78 -0
  21. package/ai/components/geo-form-modal.md +9 -10
  22. package/ai/components/geo-icon.md +3 -3
  23. package/ai/components/geo-input.md +8 -6
  24. package/ai/components/geo-layout-footer.md +70 -0
  25. package/ai/components/geo-layout-header-actions.md +82 -0
  26. package/ai/components/geo-layout-header.md +89 -0
  27. package/ai/components/geo-layout-sidebar.md +86 -0
  28. package/ai/components/geo-layout.md +155 -0
  29. package/ai/components/geo-list-page.md +72 -0
  30. package/ai/components/geo-login.md +94 -0
  31. package/ai/components/geo-map-admin-filter.md +80 -0
  32. package/ai/components/geo-map-basemap-switcher.md +75 -0
  33. package/ai/components/geo-map-help.md +72 -0
  34. package/ai/components/geo-map-layer-card.md +73 -0
  35. package/ai/components/geo-map-layer-panel.md +75 -0
  36. package/ai/components/geo-map-layers-drawer.md +78 -0
  37. package/ai/components/geo-map-legend.md +74 -0
  38. package/ai/components/geo-map-locate.md +75 -0
  39. package/ai/components/geo-map-location-chip.md +71 -0
  40. package/ai/components/geo-map-measure.md +74 -0
  41. package/ai/components/geo-map-opacity.md +75 -0
  42. package/ai/components/geo-map-parcel-popup.md +79 -0
  43. package/ai/components/geo-map-search.md +83 -0
  44. package/ai/components/geo-map-shell.md +110 -0
  45. package/ai/components/geo-map-snapshot.md +75 -0
  46. package/ai/components/geo-map-swipe.md +73 -0
  47. package/ai/components/geo-map-toolbar.md +76 -0
  48. package/ai/components/geo-map-zoom.md +74 -0
  49. package/ai/components/geo-map.md +205 -0
  50. package/ai/components/geo-overlap-result.md +88 -0
  51. package/ai/components/geo-page-header.md +72 -0
  52. package/ai/components/geo-page-title.md +1 -1
  53. package/ai/components/geo-pagination.md +4 -7
  54. package/ai/components/geo-radio.md +3 -1
  55. package/ai/components/geo-row-actions.md +3 -3
  56. package/ai/components/geo-select.md +4 -2
  57. package/ai/components/geo-slider.md +5 -7
  58. package/ai/components/geo-stat-card.md +98 -0
  59. package/ai/components/geo-status-tag.md +2 -2
  60. package/ai/components/geo-step-form-layout.md +7 -8
  61. package/ai/components/geo-stepper.md +3 -4
  62. package/ai/components/geo-table-filter.md +4 -5
  63. package/ai/components/geo-table-pagination.md +4 -7
  64. package/ai/components/geo-table-toolbar.md +7 -7
  65. package/ai/components/geo-table.md +17 -20
  66. package/ai/components/geo-tabs.md +4 -6
  67. package/ai/components/geo-textarea.md +4 -2
  68. package/ai/components/geo-toast.md +4 -4
  69. package/ai/components/geo-tree.md +4 -6
  70. package/ai/components/geo-typography.md +1 -1
  71. package/ai/components/geo-upload.md +9 -10
  72. package/ai/mockup.html +1194 -0
  73. package/ai/recipes.md +98 -85
  74. package/esm2022/lib/figma/geo-alert/geo-alert.component.mjs +19 -36
  75. package/esm2022/lib/figma/geo-back-button/geo-back-button.component.mjs +14 -24
  76. package/esm2022/lib/figma/geo-breadcrumb/geo-breadcrumb.component.mjs +8 -11
  77. package/esm2022/lib/figma/geo-button/geo-button.component.mjs +30 -59
  78. package/esm2022/lib/figma/geo-chart/geo-chart.component.mjs +88 -0
  79. package/esm2022/lib/figma/geo-chart/geo-chart.types.mjs +2 -0
  80. package/esm2022/lib/figma/geo-checkbox/geo-checkbox.component.mjs +11 -22
  81. package/esm2022/lib/figma/geo-confirm-modal/geo-confirm-modal.component.mjs +22 -54
  82. package/esm2022/lib/figma/geo-dashboard/geo-dashboard.component.mjs +49 -0
  83. package/esm2022/lib/figma/geo-dashboard/geo-dashboard.types.mjs +2 -0
  84. package/esm2022/lib/figma/geo-date-picker/geo-date-picker.component.mjs +48 -78
  85. package/esm2022/lib/figma/geo-date-range-picker/geo-date-range-picker.component.mjs +47 -75
  86. package/esm2022/lib/figma/geo-empty-state/geo-empty-state.component.mjs +25 -0
  87. package/esm2022/lib/figma/geo-feedback-form/geo-feedback-form.component.mjs +75 -0
  88. package/esm2022/lib/figma/geo-feedback-form/geo-feedback-form.types.mjs +2 -0
  89. package/esm2022/lib/figma/geo-file-picker/geo-file-picker.component.mjs +59 -81
  90. package/esm2022/lib/figma/geo-forgot-password/geo-forgot-password.component.mjs +51 -0
  91. package/esm2022/lib/figma/geo-form-modal/geo-form-modal.component.mjs +45 -112
  92. package/esm2022/lib/figma/geo-icon/geo-icon.component.mjs +22 -32
  93. package/esm2022/lib/figma/geo-input/geo-input.component.mjs +41 -70
  94. package/esm2022/lib/figma/geo-layout/footer/geo-layout-footer.component.mjs +18 -0
  95. package/esm2022/lib/figma/geo-layout/geo-layout-actions.directive.mjs +15 -0
  96. package/esm2022/lib/figma/geo-layout/geo-layout.component.mjs +79 -0
  97. package/esm2022/lib/figma/geo-layout/geo-layout.types.mjs +42 -0
  98. package/esm2022/lib/figma/geo-layout/header/geo-layout-header.component.mjs +60 -0
  99. package/esm2022/lib/figma/geo-layout/header-actions/geo-layout-header-actions.component.mjs +70 -0
  100. package/esm2022/lib/figma/geo-layout/sidebar/geo-layout-sidebar.component.mjs +90 -0
  101. package/esm2022/lib/figma/geo-list-page/geo-list-page.component.mjs +22 -0
  102. package/esm2022/lib/figma/geo-login/geo-login.component.mjs +58 -0
  103. package/esm2022/lib/figma/geo-login/geo-login.types.mjs +2 -0
  104. package/esm2022/lib/figma/geo-map/chrome/geo-map-admin-filter/geo-map-admin-filter.component.mjs +52 -0
  105. package/esm2022/lib/figma/geo-map/chrome/geo-map-basemap-switcher/geo-map-basemap-switcher.component.mjs +61 -0
  106. package/esm2022/lib/figma/geo-map/chrome/geo-map-help/geo-map-help.component.mjs +26 -0
  107. package/esm2022/lib/figma/geo-map/chrome/geo-map-layer-card/geo-map-layer-card.component.mjs +24 -0
  108. package/esm2022/lib/figma/geo-map/chrome/geo-map-layer-panel/geo-map-layer-panel.component.mjs +146 -0
  109. package/esm2022/lib/figma/geo-map/chrome/geo-map-layers-drawer/geo-map-layers-drawer.component.mjs +37 -0
  110. package/esm2022/lib/figma/geo-map/chrome/geo-map-legend/geo-map-legend.component.mjs +30 -0
  111. package/esm2022/lib/figma/geo-map/chrome/geo-map-locate/geo-map-locate.component.mjs +72 -0
  112. package/esm2022/lib/figma/geo-map/chrome/geo-map-location-chip/geo-map-location-chip.component.mjs +21 -0
  113. package/esm2022/lib/figma/geo-map/chrome/geo-map-measure/geo-map-measure.component.mjs +375 -0
  114. package/esm2022/lib/figma/geo-map/chrome/geo-map-opacity/geo-map-opacity.component.mjs +94 -0
  115. package/esm2022/lib/figma/geo-map/chrome/geo-map-parcel-popup/geo-map-parcel-popup.component.mjs +136 -0
  116. package/esm2022/lib/figma/geo-map/chrome/geo-map-search/geo-map-search.component.mjs +182 -0
  117. package/esm2022/lib/figma/geo-map/chrome/geo-map-shell/geo-map-shell.component.mjs +577 -0
  118. package/esm2022/lib/figma/geo-map/chrome/geo-map-snapshot/geo-map-snapshot.component.mjs +93 -0
  119. package/esm2022/lib/figma/geo-map/chrome/geo-map-swipe/geo-map-swipe.component.mjs +129 -0
  120. package/esm2022/lib/figma/geo-map/chrome/geo-map-toolbar/geo-map-toolbar.component.mjs +64 -0
  121. package/esm2022/lib/figma/geo-map/chrome/geo-map-zoom/geo-map-zoom.component.mjs +295 -0
  122. package/esm2022/lib/figma/geo-map/geo-map-toolbar.icons.mjs +18 -0
  123. package/esm2022/lib/figma/geo-map/geo-map.component.mjs +144 -0
  124. package/esm2022/lib/figma/geo-map/geo-map.constants.mjs +497 -0
  125. package/esm2022/lib/figma/geo-map/geo-map.controller.mjs +71 -0
  126. package/esm2022/lib/figma/geo-map/geo-map.types.mjs +2 -0
  127. package/esm2022/lib/figma/geo-map/services/geo-map-layer.service.mjs +368 -0
  128. package/esm2022/lib/figma/geo-map/services/geo-map-projection.service.mjs +110 -0
  129. package/esm2022/lib/figma/geo-map/services/geo-map.service.mjs +540 -0
  130. package/esm2022/lib/figma/geo-map/utils/geo-map-fullscreen-overlay.util.mjs +47 -0
  131. package/esm2022/lib/figma/geo-map/utils/geo-map-interactions.util.mjs +30 -0
  132. package/esm2022/lib/figma/geo-overlap-result/geo-overlap-result.component.mjs +25 -0
  133. package/esm2022/lib/figma/geo-overlap-result/geo-overlap-result.types.mjs +2 -0
  134. package/esm2022/lib/figma/geo-page-header/geo-page-header.component.mjs +23 -0
  135. package/esm2022/lib/figma/geo-page-title/geo-page-title.component.mjs +20 -35
  136. package/esm2022/lib/figma/geo-pagination/geo-pagination.component.mjs +13 -43
  137. package/esm2022/lib/figma/geo-radio/geo-radio.component.mjs +32 -52
  138. package/esm2022/lib/figma/geo-select/geo-select.component.mjs +46 -72
  139. package/esm2022/lib/figma/geo-slider/geo-slider.component.mjs +12 -28
  140. package/esm2022/lib/figma/geo-stat-card/geo-stat-card.component.mjs +163 -0
  141. package/esm2022/lib/figma/geo-stat-card/geo-stat-card.types.mjs +2 -0
  142. package/esm2022/lib/figma/geo-status-tag/geo-status-tag.component.mjs +23 -27
  143. package/esm2022/lib/figma/geo-step-form-layout/geo-step-form-layout.component.mjs +39 -96
  144. package/esm2022/lib/figma/geo-stepper/geo-stepper.component.mjs +18 -33
  145. package/esm2022/lib/figma/geo-table/geo-column-picker/geo-column-picker.component.mjs +14 -24
  146. package/esm2022/lib/figma/geo-table/geo-row-actions/geo-row-actions.component.mjs +18 -36
  147. package/esm2022/lib/figma/geo-table/geo-table-filter/geo-table-filter.component.mjs +41 -98
  148. package/esm2022/lib/figma/geo-table/geo-table-pagination/geo-table-pagination.component.mjs +40 -73
  149. package/esm2022/lib/figma/geo-table/geo-table-toolbar/geo-table-toolbar.component.mjs +26 -56
  150. package/esm2022/lib/figma/geo-table/geo-table.component.mjs +110 -210
  151. package/esm2022/lib/figma/geo-tabs/geo-tabs.component.mjs +33 -63
  152. package/esm2022/lib/figma/geo-textarea/geo-textarea.component.mjs +28 -44
  153. package/esm2022/lib/figma/geo-toast/geo-toast.component.mjs +18 -39
  154. package/esm2022/lib/figma/geo-tree/geo-tree.component.mjs +12 -40
  155. package/esm2022/lib/figma/geo-typography/geo-typography.component.mjs +49 -64
  156. package/esm2022/lib/figma/geo-upload/geo-upload.component.mjs +50 -101
  157. package/esm2022/lib/figma/index.mjs +50 -1
  158. package/esm2022/lib/styles/tokens.mjs +56 -24
  159. package/fesm2022/geoit-ui.mjs +5981 -1825
  160. package/fesm2022/geoit-ui.mjs.map +1 -1
  161. package/lib/figma/geo-alert/geo-alert.component.d.ts +10 -11
  162. package/lib/figma/geo-back-button/geo-back-button.component.d.ts +6 -7
  163. package/lib/figma/geo-breadcrumb/geo-breadcrumb.component.d.ts +2 -2
  164. package/lib/figma/geo-button/geo-button.component.d.ts +21 -17
  165. package/lib/figma/geo-chart/geo-chart.component.d.ts +40 -0
  166. package/lib/figma/geo-chart/geo-chart.types.d.ts +13 -0
  167. package/lib/figma/geo-checkbox/geo-checkbox.component.d.ts +6 -7
  168. package/lib/figma/geo-confirm-modal/geo-confirm-modal.component.d.ts +15 -17
  169. package/lib/figma/geo-dashboard/geo-dashboard.component.d.ts +29 -0
  170. package/lib/figma/geo-dashboard/geo-dashboard.types.d.ts +7 -0
  171. package/lib/figma/geo-date-picker/geo-date-picker.component.d.ts +26 -21
  172. package/lib/figma/geo-date-range-picker/geo-date-range-picker.component.d.ts +25 -20
  173. package/lib/figma/geo-empty-state/geo-empty-state.component.d.ts +17 -0
  174. package/lib/figma/geo-feedback-form/geo-feedback-form.component.d.ts +36 -0
  175. package/lib/figma/geo-feedback-form/geo-feedback-form.types.d.ts +8 -0
  176. package/lib/figma/geo-file-picker/geo-file-picker.component.d.ts +23 -20
  177. package/lib/figma/geo-forgot-password/geo-forgot-password.component.d.ts +24 -0
  178. package/lib/figma/geo-form-modal/geo-form-modal.component.d.ts +33 -35
  179. package/lib/figma/geo-icon/geo-icon.component.d.ts +7 -7
  180. package/lib/figma/geo-input/geo-input.component.d.ts +23 -21
  181. package/lib/figma/geo-layout/footer/geo-layout-footer.component.d.ts +10 -0
  182. package/lib/figma/geo-layout/geo-layout-actions.directive.d.ts +6 -0
  183. package/lib/figma/geo-layout/geo-layout.component.d.ts +48 -0
  184. package/lib/figma/geo-layout/geo-layout.types.d.ts +44 -0
  185. package/lib/figma/geo-layout/header/geo-layout-header.component.d.ts +31 -0
  186. package/lib/figma/geo-layout/header-actions/geo-layout-header-actions.component.d.ts +32 -0
  187. package/lib/figma/geo-layout/sidebar/geo-layout-sidebar.component.d.ts +34 -0
  188. package/lib/figma/geo-list-page/geo-list-page.component.d.ts +16 -0
  189. package/lib/figma/geo-login/geo-login.component.d.ts +27 -0
  190. package/lib/figma/geo-login/geo-login.types.d.ts +6 -0
  191. package/lib/figma/geo-map/chrome/geo-map-admin-filter/geo-map-admin-filter.component.d.ts +28 -0
  192. package/lib/figma/geo-map/chrome/geo-map-basemap-switcher/geo-map-basemap-switcher.component.d.ts +26 -0
  193. package/lib/figma/geo-map/chrome/geo-map-help/geo-map-help.component.d.ts +20 -0
  194. package/lib/figma/geo-map/chrome/geo-map-layer-card/geo-map-layer-card.component.d.ts +15 -0
  195. package/lib/figma/geo-map/chrome/geo-map-layer-panel/geo-map-layer-panel.component.d.ts +40 -0
  196. package/lib/figma/geo-map/chrome/geo-map-layers-drawer/geo-map-layers-drawer.component.d.ts +25 -0
  197. package/lib/figma/geo-map/chrome/geo-map-legend/geo-map-legend.component.d.ts +18 -0
  198. package/lib/figma/geo-map/chrome/geo-map-locate/geo-map-locate.component.d.ts +24 -0
  199. package/lib/figma/geo-map/chrome/geo-map-location-chip/geo-map-location-chip.component.d.ts +14 -0
  200. package/lib/figma/geo-map/chrome/geo-map-measure/geo-map-measure.component.d.ts +49 -0
  201. package/lib/figma/geo-map/chrome/geo-map-opacity/geo-map-opacity.component.d.ts +30 -0
  202. package/lib/figma/geo-map/chrome/geo-map-parcel-popup/geo-map-parcel-popup.component.d.ts +44 -0
  203. package/lib/figma/geo-map/chrome/geo-map-search/geo-map-search.component.d.ts +56 -0
  204. package/lib/figma/geo-map/chrome/geo-map-shell/geo-map-shell.component.d.ts +103 -0
  205. package/lib/figma/geo-map/chrome/geo-map-snapshot/geo-map-snapshot.component.d.ts +21 -0
  206. package/lib/figma/geo-map/chrome/geo-map-swipe/geo-map-swipe.component.d.ts +33 -0
  207. package/lib/figma/geo-map/chrome/geo-map-toolbar/geo-map-toolbar.component.d.ts +30 -0
  208. package/lib/figma/geo-map/chrome/geo-map-zoom/geo-map-zoom.component.d.ts +67 -0
  209. package/lib/figma/geo-map/geo-map-toolbar.icons.d.ts +17 -0
  210. package/lib/figma/geo-map/geo-map.component.d.ts +53 -0
  211. package/lib/figma/geo-map/geo-map.constants.d.ts +73 -0
  212. package/lib/figma/geo-map/geo-map.controller.d.ts +49 -0
  213. package/lib/figma/geo-map/geo-map.types.d.ts +224 -0
  214. package/lib/figma/geo-map/services/geo-map-layer.service.d.ts +42 -0
  215. package/lib/figma/geo-map/services/geo-map-projection.service.d.ts +32 -0
  216. package/lib/figma/geo-map/services/geo-map.service.d.ts +99 -0
  217. package/lib/figma/geo-map/utils/geo-map-fullscreen-overlay.util.d.ts +13 -0
  218. package/lib/figma/geo-map/utils/geo-map-interactions.util.d.ts +9 -0
  219. package/lib/figma/geo-overlap-result/geo-overlap-result.component.d.ts +18 -0
  220. package/lib/figma/geo-overlap-result/geo-overlap-result.types.d.ts +7 -0
  221. package/lib/figma/geo-page-header/geo-page-header.component.d.ts +16 -0
  222. package/lib/figma/geo-page-title/geo-page-title.component.d.ts +9 -9
  223. package/lib/figma/geo-pagination/geo-pagination.component.d.ts +9 -14
  224. package/lib/figma/geo-radio/geo-radio.component.d.ts +17 -15
  225. package/lib/figma/geo-select/geo-select.component.d.ts +24 -19
  226. package/lib/figma/geo-slider/geo-slider.component.d.ts +7 -9
  227. package/lib/figma/geo-stat-card/geo-stat-card.component.d.ts +50 -0
  228. package/lib/figma/geo-stat-card/geo-stat-card.types.d.ts +11 -0
  229. package/lib/figma/geo-status-tag/geo-status-tag.component.d.ts +7 -7
  230. package/lib/figma/geo-step-form-layout/geo-step-form-layout.component.d.ts +27 -29
  231. package/lib/figma/geo-stepper/geo-stepper.component.d.ts +6 -8
  232. package/lib/figma/geo-table/geo-column-picker/geo-column-picker.component.d.ts +6 -7
  233. package/lib/figma/geo-table/geo-row-actions/geo-row-actions.component.d.ts +11 -12
  234. package/lib/figma/geo-table/geo-table-filter/geo-table-filter.component.d.ts +21 -28
  235. package/lib/figma/geo-table/geo-table-pagination/geo-table-pagination.component.d.ts +17 -20
  236. package/lib/figma/geo-table/geo-table-toolbar/geo-table-toolbar.component.d.ts +17 -18
  237. package/lib/figma/geo-table/geo-table.component.d.ts +58 -62
  238. package/lib/figma/geo-tabs/geo-tabs.component.d.ts +14 -17
  239. package/lib/figma/geo-textarea/geo-textarea.component.d.ts +15 -13
  240. package/lib/figma/geo-toast/geo-toast.component.d.ts +11 -12
  241. package/lib/figma/geo-tree/geo-tree.component.d.ts +8 -13
  242. package/lib/figma/geo-typography/geo-typography.component.d.ts +13 -13
  243. package/lib/figma/geo-upload/geo-upload.component.d.ts +26 -28
  244. package/lib/figma/index.d.ts +49 -0
  245. package/lib/styles/tokens.d.ts +56 -23
  246. package/package.json +4 -2
  247. package/src/lib/figma/geo-map/assets/toolbar/fullscreen.svg +8 -0
  248. package/src/lib/figma/geo-map/assets/toolbar/home.svg +3 -0
  249. package/src/lib/figma/geo-map/assets/toolbar/layers.svg +3 -0
  250. package/src/lib/figma/geo-map/assets/toolbar/measure-area.svg +12 -0
  251. package/src/lib/figma/geo-map/assets/toolbar/measure-distance.svg +5 -0
  252. package/src/lib/figma/geo-map/assets/toolbar/pan.svg +13 -0
  253. package/src/lib/figma/geo-map/assets/toolbar/search.svg +3 -0
  254. package/src/lib/figma/geo-map/assets/toolbar/zoom-in.svg +3 -0
  255. package/src/lib/figma/geo-map/assets/toolbar/zoom-out.svg +5 -0
  256. package/src/lib/styles/design-tokens.scss +108 -35
  257. package/src/lib/styles/scrollbar.scss +2 -2
  258. package/src/lib/styles/theme.scss +1 -1
@@ -0,0 +1,375 @@
1
+ import { ChangeDetectionStrategy, Component, DestroyRef, effect, inject, input, model, output, signal, ViewEncapsulation, } from '@angular/core';
2
+ import GeometryCollection from 'ol/geom/GeometryCollection';
3
+ import { LineString, Point, Polygon } from 'ol/geom';
4
+ import Draw from 'ol/interaction/Draw';
5
+ import VectorLayer from 'ol/layer/Vector';
6
+ import { getArea, getLength } from 'ol/sphere';
7
+ import VectorSource from 'ol/source/Vector';
8
+ import { Circle as CircleStyle, Fill, Icon, Stroke, Style, Text, } from 'ol/style';
9
+ import { GEO_MAP_MEASURE_LAYER_ID } from '../../geo-map.constants';
10
+ import { pauseConflictingInteractions } from '../../utils/geo-map-interactions.util';
11
+ import * as i0 from "@angular/core";
12
+ /**
13
+ * Distance / area measure tools on the map.
14
+ *
15
+ * @summary Distance / area measure tools on the map.
16
+ * @whenToUse Đo khoảng cách / diện tích (E-tien-ich).
17
+ * @doNotUseWhen Permanent vector editing — app-owned draw tools.
18
+ */
19
+ export class GeoMapMeasureComponent {
20
+ destroyRef = inject(DestroyRef);
21
+ controller = input(null);
22
+ mode = model('none');
23
+ showResult = input(true);
24
+ measureChange = output();
25
+ result = signal(null);
26
+ source = null;
27
+ layer = null;
28
+ draw = null;
29
+ boundMap = null;
30
+ resumeInteractions = null;
31
+ constructor() {
32
+ // Writes `result` when (re)entering a measure mode — allow inside effect.
33
+ effect(() => {
34
+ const ctrl = this.controller();
35
+ const mode = this.mode();
36
+ this.syncInteraction(ctrl, mode);
37
+ }, { allowSignalWrites: true });
38
+ this.destroyRef.onDestroy(() => this.teardown());
39
+ }
40
+ ngOnDestroy() {
41
+ this.teardown();
42
+ }
43
+ clear() {
44
+ this.source?.clear();
45
+ this.result.set(null);
46
+ this.measureChange.emit(null);
47
+ this.mode.set('none');
48
+ }
49
+ syncInteraction(ctrl, mode) {
50
+ const map = ctrl?.getMap() ?? null;
51
+ if (!map) {
52
+ this.teardown();
53
+ return;
54
+ }
55
+ if (this.boundMap !== map) {
56
+ this.teardown();
57
+ this.ensureLayer(map);
58
+ this.boundMap = map;
59
+ }
60
+ else if (!this.source || !this.layer) {
61
+ this.ensureLayer(map);
62
+ }
63
+ this.removeDraw(map);
64
+ if (mode === 'none') {
65
+ // Leave cursor to the shell / host (pan grab hand, etc.).
66
+ return;
67
+ }
68
+ this.source?.clear();
69
+ this.result.set(null);
70
+ this.measureChange.emit(null);
71
+ // Double-click finishes the sketch; pause OL DoubleClickZoom while measuring.
72
+ this.resumeInteractions = pauseConflictingInteractions(map, {
73
+ dragPan: false,
74
+ doubleClickZoom: true,
75
+ });
76
+ const type = mode === 'distance' ? 'LineString' : 'Polygon';
77
+ const style = this.createStyle();
78
+ this.draw = new Draw({
79
+ source: this.source,
80
+ type,
81
+ style,
82
+ stopClick: true,
83
+ });
84
+ const capturedMode = mode;
85
+ this.draw.on('drawend', (evt) => {
86
+ const geometry = evt.feature.getGeometry();
87
+ if (!geometry) {
88
+ return;
89
+ }
90
+ const measured = this.formatResult(capturedMode, geometry);
91
+ this.result.set(measured);
92
+ this.measureChange.emit(measured);
93
+ // Exit draw mode after the Draw interaction finishes removing the sketch.
94
+ queueMicrotask(() => {
95
+ if (this.mode() === capturedMode) {
96
+ this.mode.set('none');
97
+ }
98
+ });
99
+ });
100
+ map.addInteraction(this.draw);
101
+ this.layer?.setVisible(true);
102
+ this.setMapCursor(map, 'crosshair');
103
+ }
104
+ ensureLayer(map) {
105
+ if (this.layer) {
106
+ map.removeLayer(this.layer);
107
+ }
108
+ this.source = new VectorSource();
109
+ const layer = new VectorLayer({
110
+ source: this.source,
111
+ properties: { geoLayerId: GEO_MAP_MEASURE_LAYER_ID },
112
+ style: this.createStyle(),
113
+ zIndex: 500,
114
+ updateWhileAnimating: true,
115
+ updateWhileInteracting: true,
116
+ });
117
+ this.layer = layer;
118
+ map.addLayer(layer);
119
+ }
120
+ createStyle() {
121
+ return (feature) => {
122
+ const geometry = feature.getGeometry();
123
+ if (!geometry) {
124
+ return [];
125
+ }
126
+ // Draw / Vector features expose an OL Geometry (not RenderFeature).
127
+ return this.buildMeasureStyles(geometry);
128
+ };
129
+ }
130
+ /** Dashed stroke, numbered vertices, segment labels (distance + area). */
131
+ buildMeasureStyles(geometry) {
132
+ if (!geometry) {
133
+ return [];
134
+ }
135
+ if (geometry instanceof GeometryCollection) {
136
+ return geometry
137
+ .getGeometries()
138
+ .flatMap((part) => this.buildMeasureStyles(part));
139
+ }
140
+ const color = this.cssColor('--geo-color-primary-default', '#9a4828');
141
+ const fill = this.cssColor('--geo-color-primary-default', '#9a4828', 0.12);
142
+ const fontFamily = this.cssFontFamily();
143
+ const styles = [
144
+ new Style({
145
+ fill: new Fill({ color: fill }),
146
+ stroke: new Stroke({
147
+ color,
148
+ width: 2,
149
+ lineDash: [7, 7],
150
+ }),
151
+ }),
152
+ ];
153
+ if (geometry instanceof Point) {
154
+ styles.push(...this.vertexStyles(geometry.getCoordinates(), 1, color));
155
+ return styles;
156
+ }
157
+ let points = [];
158
+ if (geometry instanceof LineString) {
159
+ points = geometry.getCoordinates();
160
+ }
161
+ else if (geometry instanceof Polygon) {
162
+ const ring = geometry.getCoordinates()[0] ?? [];
163
+ points = this.openRing(ring);
164
+ }
165
+ if (!points.length) {
166
+ return styles;
167
+ }
168
+ for (let i = 0; i < points.length; i++) {
169
+ styles.push(...this.vertexStyles(points[i], i + 1, color));
170
+ }
171
+ const closed = geometry instanceof Polygon && points.length >= 2;
172
+ const segmentCount = closed ? points.length : Math.max(0, points.length - 1);
173
+ for (let i = 0; i < segmentCount; i++) {
174
+ const a = points[i];
175
+ const b = points[(i + 1) % points.length];
176
+ styles.push(this.segmentLabelStyle(a, b, color, fontFamily));
177
+ }
178
+ if (geometry instanceof Polygon && points.length >= 3) {
179
+ const areaLabel = this.areaCentroidLabel(geometry, color, fontFamily);
180
+ if (areaLabel) {
181
+ styles.push(areaLabel);
182
+ }
183
+ }
184
+ return styles;
185
+ }
186
+ openRing(ring) {
187
+ if (ring.length < 2) {
188
+ return ring;
189
+ }
190
+ const first = ring[0];
191
+ const last = ring[ring.length - 1];
192
+ if (first[0] === last[0] && first[1] === last[1]) {
193
+ return ring.slice(0, -1);
194
+ }
195
+ return ring;
196
+ }
197
+ vertexStyles(coord, index, color) {
198
+ return [
199
+ new Style({
200
+ geometry: new Point(coord),
201
+ image: new CircleStyle({
202
+ radius: 3.5,
203
+ fill: new Fill({ color }),
204
+ }),
205
+ }),
206
+ new Style({
207
+ geometry: new Point(coord),
208
+ image: new Icon({
209
+ src: this.numberBadgeDataUrl(index, color),
210
+ anchor: [0.5, 1.35],
211
+ anchorXUnits: 'fraction',
212
+ anchorYUnits: 'fraction',
213
+ scale: 1,
214
+ }),
215
+ }),
216
+ ];
217
+ }
218
+ numberBadgeDataUrl(index, color) {
219
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 22 22">` +
220
+ `<circle cx="11" cy="11" r="10" fill="${color}"/>` +
221
+ `<text x="11" y="15" text-anchor="middle" fill="#ffffff" ` +
222
+ `font-size="11" font-weight="700" font-family="sans-serif">${index}</text>` +
223
+ `</svg>`;
224
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
225
+ }
226
+ segmentLabelStyle(a, b, color, fontFamily) {
227
+ const mid = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
228
+ const meters = getLength(new LineString([a, b]));
229
+ let rotation = -Math.atan2(b[1] - a[1], b[0] - a[0]);
230
+ // Keep labels upright/readable.
231
+ if (rotation > Math.PI / 2 || rotation < -Math.PI / 2) {
232
+ rotation += Math.PI;
233
+ }
234
+ return new Style({
235
+ geometry: new Point(mid),
236
+ text: new Text({
237
+ text: this.formatLengthLabel(meters),
238
+ font: `500 12px ${fontFamily}`,
239
+ fill: new Fill({ color }),
240
+ stroke: new Stroke({
241
+ color: 'rgba(255, 255, 255, 0.9)',
242
+ width: 3,
243
+ }),
244
+ rotation,
245
+ rotateWithView: true,
246
+ textAlign: 'center',
247
+ textBaseline: 'middle',
248
+ }),
249
+ });
250
+ }
251
+ areaCentroidLabel(geometry, color, fontFamily) {
252
+ const interior = geometry.getInteriorPoint()?.getCoordinates();
253
+ if (!interior) {
254
+ return null;
255
+ }
256
+ const sqMeters = getArea(geometry);
257
+ return new Style({
258
+ geometry: new Point(interior),
259
+ text: new Text({
260
+ text: this.formatAreaLabel(sqMeters),
261
+ font: `600 12px ${fontFamily}`,
262
+ fill: new Fill({ color }),
263
+ stroke: new Stroke({
264
+ color: 'rgba(255, 255, 255, 0.92)',
265
+ width: 3.5,
266
+ }),
267
+ textAlign: 'center',
268
+ textBaseline: 'middle',
269
+ }),
270
+ });
271
+ }
272
+ formatLengthLabel(meters) {
273
+ if (meters >= 1000) {
274
+ return `${(meters / 1000).toFixed(1)} km`;
275
+ }
276
+ return `${meters.toFixed(1)} m`;
277
+ }
278
+ formatAreaLabel(sqMeters) {
279
+ if (sqMeters >= 10_000) {
280
+ return `${(sqMeters / 10_000).toFixed(2)} ha`;
281
+ }
282
+ return `${sqMeters.toFixed(1)} m²`;
283
+ }
284
+ /** Resolve a design token for OpenLayers canvas styles. */
285
+ cssColor(token, fallback, alpha) {
286
+ if (typeof document === 'undefined') {
287
+ return alpha != null ? this.withAlpha(fallback, alpha) : fallback;
288
+ }
289
+ const raw = getComputedStyle(document.documentElement)
290
+ .getPropertyValue(token)
291
+ .trim();
292
+ const color = raw || fallback;
293
+ return alpha != null ? this.withAlpha(color, alpha) : color;
294
+ }
295
+ cssFontFamily() {
296
+ if (typeof document === 'undefined') {
297
+ return 'sans-serif';
298
+ }
299
+ const raw = getComputedStyle(document.documentElement)
300
+ .getPropertyValue('--geo-font-family')
301
+ .trim();
302
+ return raw || 'sans-serif';
303
+ }
304
+ withAlpha(color, alpha) {
305
+ const hex = color.match(/^#([0-9a-f]{6})$/i);
306
+ if (hex) {
307
+ const n = parseInt(hex[1], 16);
308
+ const r = (n >> 16) & 255;
309
+ const g = (n >> 8) & 255;
310
+ const b = n & 255;
311
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
312
+ }
313
+ return color;
314
+ }
315
+ formatResult(mode, geometry) {
316
+ if (mode === 'distance' && geometry instanceof LineString) {
317
+ const meters = getLength(geometry);
318
+ return {
319
+ mode,
320
+ value: meters,
321
+ label: this.formatLengthLabel(meters),
322
+ geometry,
323
+ };
324
+ }
325
+ if (mode === 'area' && geometry instanceof Polygon) {
326
+ const sqMeters = getArea(geometry);
327
+ return {
328
+ mode,
329
+ value: sqMeters,
330
+ label: this.formatAreaLabel(sqMeters),
331
+ geometry,
332
+ };
333
+ }
334
+ return { mode, value: 0, label: '-', geometry };
335
+ }
336
+ removeDraw(map) {
337
+ if (this.draw) {
338
+ map.removeInteraction(this.draw);
339
+ this.draw = null;
340
+ }
341
+ this.resumeInteractions?.();
342
+ this.resumeInteractions = null;
343
+ }
344
+ setMapCursor(map, cursor) {
345
+ const el = map.getTargetElement();
346
+ if (!el) {
347
+ return;
348
+ }
349
+ el.style.cursor = cursor ?? '';
350
+ }
351
+ teardown() {
352
+ const map = this.boundMap ?? this.controller()?.getMap() ?? null;
353
+ if (map) {
354
+ this.removeDraw(map);
355
+ this.setMapCursor(map, null);
356
+ if (this.layer) {
357
+ map.removeLayer(this.layer);
358
+ }
359
+ }
360
+ this.draw = null;
361
+ this.layer = null;
362
+ this.source = null;
363
+ this.boundMap = null;
364
+ }
365
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoMapMeasureComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
366
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoMapMeasureComponent, isStandalone: true, selector: "geo-map-measure", inputs: { controller: { classPropertyName: "controller", publicName: "controller", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, showResult: { classPropertyName: "showResult", publicName: "showResult", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { mode: "modeChange", measureChange: "measureChange" }, host: { properties: { "class.geo-map-measure-host--active": "mode() !== \"none\"" }, classAttribute: "geo-map-measure-host" }, ngImport: i0, template: "@if (showResult() && result(); as measured) {\n <div class=\"geo-map-measure__result\" role=\"status\">\n <span class=\"geo-map-measure__result-label\">\n {{ measured.mode === 'distance' ? 'Kho\u1EA3ng c\u00E1ch' : 'Di\u1EC7n t\u00EDch' }}:\n <strong>{{ measured.label }}</strong>\n </span>\n <button\n type=\"button\"\n class=\"geo-map-measure__clear\"\n (click)=\"clear()\"\n >\n X\u00F3a\n </button>\n </div>\n}\n\n@if (mode() !== 'none') {\n <div class=\"geo-map-measure__hint\" role=\"status\">\n {{\n mode() === 'distance'\n ? 'Nh\u1EA5p c\u00E1c \u0111i\u1EC3m \u0111\u1EC3 \u0111o kho\u1EA3ng c\u00E1ch. Nh\u00E1y \u0111\u00FAp \u0111\u1EC3 k\u1EBFt th\u00FAc.'\n : 'Nh\u1EA5p c\u00E1c \u0111i\u1EC3m \u0111\u1EC3 \u0111o di\u1EC7n t\u00EDch. Nh\u00E1y \u0111\u00FAp \u0111\u1EC3 k\u1EBFt th\u00FAc.'\n }}\n <button type=\"button\" class=\"geo-map-measure__clear\" (click)=\"clear()\">\n H\u1EE7y\n </button>\n </div>\n}\n", styles: ["@charset \"UTF-8\";.geo-map-measure-host{display:contents}.geo-map-measure__result,.geo-map-measure__hint{border:1px solid var(--geo-color-border-default);border-radius:var(--geo-radius-lg);background:var(--geo-color-surface-elevated);box-shadow:var(--geo-shadow-sm);display:inline-flex;align-items:center;gap:10px;padding:8px 12px;font-size:var(--geo-font-size-body-small);color:var(--geo-color-neutral-800);pointer-events:auto}.geo-map-measure__result-label strong{color:var(--geo-color-primary-default);font-weight:var(--geo-font-weight-semibold)}.geo-map-measure__clear{border:0;border-radius:var(--geo-radius);background:var(--geo-color-primary-soft);color:var(--geo-color-primary-default);font:inherit;font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-semibold);padding:4px 8px;cursor:pointer}.geo-map-measure__clear:hover{background:var(--geo-color-primary-soft-hover)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
367
+ }
368
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoMapMeasureComponent, decorators: [{
369
+ type: Component,
370
+ args: [{ selector: 'geo-map-measure', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
371
+ class: 'geo-map-measure-host',
372
+ '[class.geo-map-measure-host--active]': 'mode() !== "none"',
373
+ }, template: "@if (showResult() && result(); as measured) {\n <div class=\"geo-map-measure__result\" role=\"status\">\n <span class=\"geo-map-measure__result-label\">\n {{ measured.mode === 'distance' ? 'Kho\u1EA3ng c\u00E1ch' : 'Di\u1EC7n t\u00EDch' }}:\n <strong>{{ measured.label }}</strong>\n </span>\n <button\n type=\"button\"\n class=\"geo-map-measure__clear\"\n (click)=\"clear()\"\n >\n X\u00F3a\n </button>\n </div>\n}\n\n@if (mode() !== 'none') {\n <div class=\"geo-map-measure__hint\" role=\"status\">\n {{\n mode() === 'distance'\n ? 'Nh\u1EA5p c\u00E1c \u0111i\u1EC3m \u0111\u1EC3 \u0111o kho\u1EA3ng c\u00E1ch. Nh\u00E1y \u0111\u00FAp \u0111\u1EC3 k\u1EBFt th\u00FAc.'\n : 'Nh\u1EA5p c\u00E1c \u0111i\u1EC3m \u0111\u1EC3 \u0111o di\u1EC7n t\u00EDch. Nh\u00E1y \u0111\u00FAp \u0111\u1EC3 k\u1EBFt th\u00FAc.'\n }}\n <button type=\"button\" class=\"geo-map-measure__clear\" (click)=\"clear()\">\n H\u1EE7y\n </button>\n </div>\n}\n", styles: ["@charset \"UTF-8\";.geo-map-measure-host{display:contents}.geo-map-measure__result,.geo-map-measure__hint{border:1px solid var(--geo-color-border-default);border-radius:var(--geo-radius-lg);background:var(--geo-color-surface-elevated);box-shadow:var(--geo-shadow-sm);display:inline-flex;align-items:center;gap:10px;padding:8px 12px;font-size:var(--geo-font-size-body-small);color:var(--geo-color-neutral-800);pointer-events:auto}.geo-map-measure__result-label strong{color:var(--geo-color-primary-default);font-weight:var(--geo-font-weight-semibold)}.geo-map-measure__clear{border:0;border-radius:var(--geo-radius);background:var(--geo-color-primary-soft);color:var(--geo-color-primary-default);font:inherit;font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-semibold);padding:4px 8px;cursor:pointer}.geo-map-measure__clear:hover{background:var(--geo-color-primary-soft-hover)}\n"] }]
374
+ }], ctorParameters: () => [] });
375
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VvLW1hcC1tZWFzdXJlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2dlby11aS9zcmMvbGliL2ZpZ21hL2dlby1tYXAvY2hyb21lL2dlby1tYXAtbWVhc3VyZS9nZW8tbWFwLW1lYXN1cmUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZ2VvLXVpL3NyYy9saWIvZmlnbWEvZ2VvLW1hcC9jaHJvbWUvZ2VvLW1hcC1tZWFzdXJlL2dlby1tYXAtbWVhc3VyZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxVQUFVLEVBQ1YsTUFBTSxFQUNOLE1BQU0sRUFDTixLQUFLLEVBQ0wsS0FBSyxFQUVMLE1BQU0sRUFDTixNQUFNLEVBQ04saUJBQWlCLEdBQ2xCLE1BQU0sZUFBZSxDQUFDO0FBR3ZCLE9BQU8sa0JBQWtCLE1BQU0sNEJBQTRCLENBQUM7QUFDNUQsT0FBTyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ3JELE9BQU8sSUFBSSxNQUFNLHFCQUFxQixDQUFDO0FBRXZDLE9BQU8sV0FBVyxNQUFNLGlCQUFpQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQy9DLE9BQU8sWUFBWSxNQUFNLGtCQUFrQixDQUFDO0FBRTVDLE9BQU8sRUFDTCxNQUFNLElBQUksV0FBVyxFQUNyQixJQUFJLEVBQ0osSUFBSSxFQUNKLE1BQU0sRUFDTixLQUFLLEVBQ0wsSUFBSSxHQUNMLE1BQU0sVUFBVSxDQUFDO0FBQ2xCLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ25FLE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxNQUFNLHVD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QXNCO2tCQWJsQyxTQUFTOytCQUNFLGlCQUFpQixjQUNmLElBQUksV0FDUCxFQUFFLG1CQUdNLHVCQUF1QixDQUFDLE1BQU0saUJBQ2hDLGlCQUFpQixDQUFDLElBQUksUUFDL0I7d0JBQ0osS0FBSyxFQUFFLHNCQUFzQjt3QkFDN0Isc0NBQXNDLEVBQUUsbUJBQW1CO3FCQUM1RCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDb21wb25lbnQsXG4gIERlc3Ryb3lSZWYsXG4gIGVmZmVjdCxcbiAgaW5qZWN0LFxuICBpbnB1dCxcbiAgbW9kZWwsXG4gIE9uRGVzdHJveSxcbiAgb3V0cHV0LFxuICBzaWduYWwsXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB0eXBlIHsgRmVhdHVyZUxpa2UgfSBmcm9tICdvbC9GZWF0dXJlJztcbmltcG9ydCB0eXBlIEdlb21ldHJ5IGZyb20gJ29sL2dlb20vR2VvbWV0cnknO1xuaW1wb3J0IEdlb21ldHJ5Q29sbGVjdGlvbiBmcm9tICdvbC9nZW9tL0dlb21ldHJ5Q29sbGVjdGlvbic7XG5pbXBvcnQgeyBMaW5lU3RyaW5nLCBQb2ludCwgUG9seWdvbiB9IGZyb20gJ29sL2dlb20nO1xuaW1wb3J0IERyYXcgZnJvbSAnb2wvaW50ZXJhY3Rpb24vRHJhdyc7XG5pbXBvcnQgdHlwZSBPbE1hcCBmcm9tICdvbC9NYXAnO1xuaW1wb3J0IFZlY3RvckxheWVyIGZyb20gJ29sL2xheWVyL1ZlY3Rvcic7XG5pbXBvcnQgeyBnZXRBcmVhLCBnZXRMZW5ndGggfSBmcm9tICdvbC9zcGhlcmUnO1xuaW1wb3J0IFZlY3RvclNvdXJjZSBmcm9tICdvbC9zb3VyY2UvVmVjdG9yJztcbmltcG9ydCB0eXBlIHsgU3R5bGVMaWtlIH0gZnJvbSAnb2wvc3R5bGUvU3R5bGUnO1xuaW1wb3J0IHtcbiAgQ2lyY2xlIGFzIENpcmNsZVN0eWxlLFxuICBGaWxsLFxuICBJY29uLFxuICBTdHJva2UsXG4gIFN0eWxlLFxuICBUZXh0LFxufSBmcm9tICdvbC9zdHlsZSc7XG5pbXBvcnQgeyBHRU9fTUFQX01FQVNVUkVfTEFZRVJfSUQgfSBmcm9tICcuLi8uLi9nZW8tbWFwLmNvbnN0YW50cyc7XG5pbXBvcnQgeyBwYXVzZUNvbmZsaWN0aW5nSW50ZXJhY3Rpb25zIH0gZnJvbSAnLi4vLi4vdXRpbHMvZ2VvLW1hcC1pbnRlcmFjdGlvbnMudXRpbCc7XG5pbXBvcnQgeyBHZW9NYXBDb250cm9sbGVyIH0gZnJvbSAnLi4vLi4vZ2VvLW1hcC5jb250cm9sbGVyJztcbmltcG9ydCB0eXBlIHsgR2VvTWFwTWVhc3VyZU1vZGUsIEdlb01hcE1lYXN1cmVSZXN1bHQgfSBmcm9tICcuLi8uLi9nZW8tbWFwLnR5cGVzJztcblxuLyoqXG4gKiBEaXN0YW5jZSAvIGFyZWEgbWVhc3VyZSB0b29scyBvbiB0aGUgbWFwLlxuICpcbiAqIEBzdW1tYXJ5IERpc3RhbmNlIC8gYXJlYSBtZWFzdXJlIHRvb2xzIG9uIHRoZSBtYXAuXG4gKiBAd2hlblRvVXNlIMSQbyBraG/huqNuZyBjw6FjaCAvIGRp4buHbiB0w61jaCAoRS10aWVuLWljaCkuXG4gKiBAZG9Ob3RVc2VXaGVuIFBlcm1hbmVudCB2ZWN0b3IgZWRpdGluZyDigJQgYXBwLW93bmVkIGRyYXcgdG9vbHMuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2dlby1tYXAtbWVhc3VyZScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtdLFxuICB0ZW1wbGF0ZVVybDogJy4vZ2VvLW1hcC1tZWFzdXJlLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmw6ICcuL2dlby1tYXAtbWVhc3VyZS5jb21wb25lbnQuc2NzcycsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBob3N0OiB7XG4gICAgY2xhc3M6ICdnZW8tbWFwLW1lYXN1cmUtaG9zdCcsXG4gICAgJ1tjbGFzcy5nZW8tbWFwLW1lYXN1cmUtaG9zdC0tYWN0aXZlXSc6ICdtb2RlKCkgIT09IFwibm9uZVwiJyxcbiAgfSxcbn0pXG5leHBvcnQgY2xhc3MgR2VvTWFwTWVhc3VyZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uRGVzdHJveSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVzdHJveVJlZiA9IGluamVjdChEZXN0cm95UmVmKTtcblxuICByZWFkb25seSBjb250cm9sbGVyID0gaW5wdXQ8R2VvTWFwQ29udHJvbGxlciB8IG51bGw+KG51bGwpO1xuICByZWFkb25seSBtb2RlID0gbW9kZWw8R2VvTWFwTWVhc3VyZU1vZGU+KCdub25lJyk7XG4gIHJlYWRvbmx5IHNob3dSZXN1bHQgPSBpbnB1dCh0cnVlKTtcblxuICByZWFkb25seSBtZWFzdXJlQ2hhbmdlID0gb3V0cHV0PEdlb01hcE1lYXN1cmVSZXN1bHQgfCBudWxsPigpO1xuXG4gIHJlYWRvbmx5IHJlc3VsdCA9IHNpZ25hbDxHZW9NYXBNZWFzdXJlUmVzdWx0IHwgbnVsbD4obnVsbCk7XG5cbiAgcHJpdmF0ZSBzb3VyY2U6IFZlY3RvclNvdXJjZSB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGxheWVyOiBWZWN0b3JMYXllcjxWZWN0b3JTb3VyY2U+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZHJhdzogRHJhdyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGJvdW5kTWFwOiBPbE1hcCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHJlc3VtZUludGVyYWN0aW9uczogKCgpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gV3JpdGVzIGByZXN1bHRgIHdoZW4gKHJlKWVudGVyaW5nIGEgbWVhc3VyZSBtb2RlIOKAlCBhbGxvdyBpbnNpZGUgZWZmZWN0LlxuICAgIGVmZmVjdChcbiAgICAgICgpID0+IHtcbiAgICAgICAgY29uc3QgY3RybCA9IHRoaXMuY29udHJvbGxlcigpO1xuICAgICAgICBjb25zdCBtb2RlID0gdGhpcy5tb2RlKCk7XG4gICAgICAgIHRoaXMuc3luY0ludGVyYWN0aW9uKGN0cmwsIG1vZGUpO1xuICAgICAgfSxcbiAgICAgIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfSxcbiAgICApO1xuXG4gICAgdGhpcy5kZXN0cm95UmVmLm9uRGVzdHJveSgoKSA9PiB0aGlzLnRlYXJkb3duKCkpO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy50ZWFyZG93bigpO1xuICB9XG5cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy5zb3VyY2U/LmNsZWFyKCk7XG4gICAgdGhpcy5yZXN1bHQuc2V0KG51bGwpO1xuICAgIHRoaXMubWVhc3VyZUNoYW5nZS5lbWl0KG51bGwpO1xuICAgIHRoaXMubW9kZS5zZXQoJ25vbmUnKTtcbiAgfVxuXG4gIHByaXZhdGUgc3luY0ludGVyYWN0aW9uKFxuICAgIGN0cmw6IEdlb01hcENvbnRyb2xsZXIgfCBudWxsLFxuICAgIG1vZGU6IEdlb01hcE1lYXN1cmVNb2RlLFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBtYXAgPSBjdHJsPy5nZXRNYXAoKSA/PyBudWxsO1xuICAgIGlmICghbWFwKSB7XG4gICAgICB0aGlzLnRlYXJkb3duKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuYm91bmRNYXAgIT09IG1hcCkge1xuICAgICAgdGhpcy50ZWFyZG93bigpO1xuICAgICAgdGhpcy5lbnN1cmVMYXllcihtYXApO1xuICAgICAgdGhpcy5ib3VuZE1hcCA9IG1hcDtcbiAgICB9IGVsc2UgaWYgKCF0aGlzLnNvdXJjZSB8fCAhdGhpcy5sYXllcikge1xuICAgICAgdGhpcy5lbnN1cmVMYXllcihtYXApO1xuICAgIH1cblxuICAgIHRoaXMucmVtb3ZlRHJhdyhtYXApO1xuXG4gICAgaWYgKG1vZGUgPT09ICdub25lJykge1xuICAgICAgLy8gTGVhdmUgY3Vyc29yIHRvIHRoZSBzaGVsbCAvIGhvc3QgKHBhbiBncmFiIGhhbmQsIGV0Yy4pLlxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuc291cmNlPy5jbGVhcigpO1xuICAgIHRoaXMucmVzdWx0LnNldChudWxsKTtcbiAgICB0aGlzLm1lYXN1cmVDaGFuZ2UuZW1pdChudWxsKTtcblxuICAgIC8vIERvdWJsZS1jbGljayBmaW5pc2hlcyB0aGUgc2tldGNoOyBwYXVzZSBPTCBEb3VibGVDbGlja1pvb20gd2hpbGUgbWVhc3VyaW5nLlxuICAgIHRoaXMucmVzdW1lSW50ZXJhY3Rpb25zID0gcGF1c2VDb25mbGljdGluZ0ludGVyYWN0aW9ucyhtYXAsIHtcbiAgICAgIGRyYWdQYW46IGZhbHNlLFxuICAgICAgZG91YmxlQ2xpY2tab29tOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgY29uc3QgdHlwZSA9IG1vZGUgPT09ICdkaXN0YW5jZScgPyAnTGluZVN0cmluZycgOiAnUG9seWdvbic7XG4gICAgY29uc3Qgc3R5bGUgPSB0aGlzLmNyZWF0ZVN0eWxlKCk7XG4gICAgdGhpcy5kcmF3ID0gbmV3IERyYXcoe1xuICAgICAgc291cmNlOiB0aGlzLnNvdXJjZSEsXG4gICAgICB0eXBlLFxuICAgICAgc3R5bGUsXG4gICAgICBzdG9wQ2xpY2s6IHRydWUsXG4gICAgfSk7XG5cbiAgICBjb25zdCBjYXB0dXJlZE1vZGUgPSBtb2RlO1xuICAgIHRoaXMuZHJhdy5vbignZHJhd2VuZCcsIChldnQpID0+IHtcbiAgICAgIGNvbnN0IGdlb21ldHJ5ID0gZXZ0LmZlYXR1cmUuZ2V0R2VvbWV0cnkoKTtcbiAgICAgIGlmICghZ2VvbWV0cnkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY29uc3QgbWVhc3VyZWQgPSB0aGlzLmZvcm1hdFJlc3VsdChjYXB0dXJlZE1vZGUsIGdlb21ldHJ5KTtcbiAgICAgIHRoaXMucmVzdWx0LnNldChtZWFzdXJlZCk7XG4gICAgICB0aGlzLm1lYXN1cmVDaGFuZ2UuZW1pdChtZWFzdXJlZCk7XG4gICAgICAvLyBFeGl0IGRyYXcgbW9kZSBhZnRlciB0aGUgRHJhdyBpbnRlcmFjdGlvbiBmaW5pc2hlcyByZW1vdmluZyB0aGUgc2tldGNoLlxuICAgICAgcXVldWVNaWNyb3Rhc2soKCkgPT4ge1xuICAgICAgICBpZiAodGhpcy5tb2RlKCkgPT09IGNhcHR1cmVkTW9kZSkge1xuICAgICAgICAgIHRoaXMubW9kZS5zZXQoJ25vbmUnKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBtYXAuYWRkSW50ZXJhY3Rpb24odGhpcy5kcmF3KTtcbiAgICB0aGlzLmxheWVyPy5zZXRWaXNpYmxlKHRydWUpO1xuICAgIHRoaXMuc2V0TWFwQ3Vyc29yKG1hcCwgJ2Nyb3NzaGFpcicpO1xuICB9XG5cbiAgcHJpdmF0ZSBlbnN1cmVMYXllcihtYXA6IE9sTWFwKTogdm9pZCB7XG4gICAgaWYgKHRoaXMubGF5ZXIpIHtcbiAgICAgIG1hcC5yZW1vdmVMYXllcih0aGlzLmxheWVyKTtcbiAgICB9XG4gICAgdGhpcy5zb3VyY2UgPSBuZXcgVmVjdG9yU291cmNlKCk7XG4gICAgY29uc3QgbGF5ZXIgPSBuZXcgVmVjdG9yTGF5ZXIoe1xuICAgICAgc291cmNlOiB0aGlzLnNvdXJjZSxcbiAgICAgIHByb3BlcnRpZXM6IHsgZ2VvTGF5ZXJJZDogR0VPX01BUF9NRUFTVVJFX0xBWUVSX0lEIH0sXG4gICAgICBzdHlsZTogdGhpcy5jcmVhdGVTdHlsZSgpLFxuICAgICAgekluZGV4OiA1MDAsXG4gICAgICB1cGRhdGVXaGlsZUFuaW1hdGluZzogdHJ1ZSxcbiAgICAgIHVwZGF0ZVdoaWxlSW50ZXJhY3Rpbmc6IHRydWUsXG4gICAgfSk7XG4gICAgdGhpcy5sYXllciA9IGxheWVyO1xuICAgIG1hcC5hZGRMYXllcihsYXllcik7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZVN0eWxlKCk6IFN0eWxlTGlrZSB7XG4gICAgcmV0dXJuIChmZWF0dXJlOiBGZWF0dXJlTGlrZSkgPT4ge1xuICAgICAgY29uc3QgZ2VvbWV0cnkgPSBmZWF0dXJlLmdldEdlb21ldHJ5KCk7XG4gICAgICBpZiAoIWdlb21ldHJ5KSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cbiAgICAgIC8vIERyYXcgLyBWZWN0b3IgZmVhdHVyZXMgZXhwb3NlIGFuIE9MIEdlb21ldHJ5IChub3QgUmVuZGVyRmVhdHVyZSkuXG4gICAgICByZXR1cm4gdGhpcy5idWlsZE1lYXN1cmVTdHlsZXMoZ2VvbWV0cnkgYXMgR2VvbWV0cnkpO1xuICAgIH07XG4gIH1cblxuICAvKiogRGFzaGVkIHN0cm9rZSwgbnVtYmVyZWQgdmVydGljZXMsIHNlZ21lbnQgbGFiZWxzIChkaXN0YW5jZSArIGFyZWEpLiAqL1xuICBwcml2YXRlIGJ1aWxkTWVhc3VyZVN0eWxlcyhnZW9tZXRyeTogR2VvbWV0cnkgfCBudWxsKTogU3R5bGVbXSB7XG4gICAgaWYgKCFnZW9tZXRyeSkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cblxuICAgIGlmIChnZW9tZXRyeSBpbnN0YW5jZW9mIEdlb21ldHJ5Q29sbGVjdGlvbikge1xuICAgICAgcmV0dXJuIGdlb21ldHJ5XG4gICAgICAgIC5nZXRHZW9tZXRyaWVzKClcbiAgICAgICAgLmZsYXRNYXAoKHBhcnQpID0+IHRoaXMuYnVpbGRNZWFzdXJlU3R5bGVzKHBhcnQpKTtcbiAgICB9XG5cbiAgICBjb25zdCBjb2xvciA9IHRoaXMuY3NzQ29sb3IoJy0tZ2VvLWNvbG9yLXByaW1hcnktZGVmYXVsdCcsICcjOWE0ODI4Jyk7XG4gICAgY29uc3QgZmlsbCA9IHRoaXMuY3NzQ29sb3IoJy0tZ2VvLWNvbG9yLXByaW1hcnktZGVmYXVsdCcsICcjOWE0ODI4JywgMC4xMik7XG4gICAgY29uc3QgZm9udEZhbWlseSA9IHRoaXMuY3NzRm9udEZhbWlseSgpO1xuICAgIGNvbnN0IHN0eWxlczogU3R5bGVbXSA9IFtcbiAgICAgIG5ldyBTdHlsZSh7XG4gICAgICAgIGZpbGw6IG5ldyBGaWxsKHsgY29sb3I6IGZpbGwgfSksXG4gICAgICAgIHN0cm9rZTogbmV3IFN0cm9rZSh7XG4gICAgICAgICAgY29sb3IsXG4gICAgICAgICAgd2lkdGg6IDIsXG4gICAgICAgICAgbGluZURhc2g6IFs3LCA3XSxcbiAgICAgICAgfSksXG4gICAgICB9KSxcbiAgICBdO1xuXG4gICAgaWYgKGdlb21ldHJ5IGluc3RhbmNlb2YgUG9pbnQpIHtcbiAgICAgIHN0eWxlcy5wdXNoKC4uLnRoaXMudmVydGV4U3R5bGVzKGdlb21ldHJ5LmdldENvb3JkaW5hdGVzKCksIDEsIGNvbG9yKSk7XG4gICAgICByZXR1cm4gc3R5bGVzO1xuICAgIH1cblxuICAgIGxldCBwb2ludHM6IG51bWJlcltdW10gPSBbXTtcbiAgICBpZiAoZ2VvbWV0cnkgaW5zdGFuY2VvZiBMaW5lU3RyaW5nKSB7XG4gICAgICBwb2ludHMgPSBnZW9tZXRyeS5nZXRDb29yZGluYXRlcygpO1xuICAgIH0gZWxzZSBpZiAoZ2VvbWV0cnkgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICBjb25zdCByaW5nID0gZ2VvbWV0cnkuZ2V0Q29vcmRpbmF0ZXMoKVswXSA/PyBbXTtcbiAgICAgIHBvaW50cyA9IHRoaXMub3BlblJpbmcocmluZyk7XG4gICAgfVxuXG4gICAgaWYgKCFwb2ludHMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gc3R5bGVzO1xuICAgIH1cblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBzdHlsZXMucHVzaCguLi50aGlzLnZlcnRleFN0eWxlcyhwb2ludHNbaV0sIGkgKyAxLCBjb2xvcikpO1xuICAgIH1cblxuICAgIGNvbnN0IGNsb3NlZCA9IGdlb21ldHJ5IGluc3RhbmNlb2YgUG9seWdvbiAmJiBwb2ludHMubGVuZ3RoID49IDI7XG4gICAgY29uc3Qgc2VnbWVudENvdW50ID0gY2xvc2VkID8gcG9pbnRzLmxlbmd0aCA6IE1hdGgubWF4KDAsIHBvaW50cy5sZW5ndGggLSAxKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNlZ21lbnRDb3VudDsgaSsrKSB7XG4gICAgICBjb25zdCBhID0gcG9pbnRzW2ldO1xuICAgICAgY29uc3QgYiA9IHBvaW50c1soaSArIDEpICUgcG9pbnRzLmxlbmd0aF07XG4gICAgICBzdHlsZXMucHVzaCh0aGlzLnNlZ21lbnRMYWJlbFN0eWxlKGEsIGIsIGNvbG9yLCBmb250RmFtaWx5KSk7XG4gICAgfVxuXG4gICAgaWYgKGdlb21ldHJ5IGluc3RhbmNlb2YgUG9seWdvbiAmJiBwb2ludHMubGVuZ3RoID49IDMpIHtcbiAgICAgIGNvbnN0IGFyZWFMYWJlbCA9IHRoaXMuYXJlYUNlbnRyb2lkTGFiZWwoZ2VvbWV0cnksIGNvbG9yLCBmb250RmFtaWx5KTtcbiAgICAgIGlmIChhcmVhTGFiZWwpIHtcbiAgICAgICAgc3R5bGVzLnB1c2goYXJlYUxhYmVsKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gc3R5bGVzO1xuICB9XG5cbiAgcHJpdmF0ZSBvcGVuUmluZyhyaW5nOiBudW1iZXJbXVtdKTogbnVtYmVyW11bXSB7XG4gICAgaWYgKHJpbmcubGVuZ3RoIDwgMikge1xuICAgICAgcmV0dXJuIHJpbmc7XG4gICAgfVxuICAgIGNvbnN0IGZpcnN0ID0gcmluZ1swXTtcbiAgICBjb25zdCBsYXN0ID0gcmluZ1tyaW5nLmxlbmd0aCAtIDFdO1xuICAgIGlmIChmaXJzdFswXSA9PT0gbGFzdFswXSAmJiBmaXJzdFsxXSA9PT0gbGFzdFsxXSkge1xuICAgICAgcmV0dXJuIHJpbmcuc2xpY2UoMCwgLTEpO1xuICAgIH1cbiAgICByZXR1cm4gcmluZztcbiAgfVxuXG4gIHByaXZhdGUgdmVydGV4U3R5bGVzKGNvb3JkOiBudW1iZXJbXSwgaW5kZXg6IG51bWJlciwgY29sb3I6IHN0cmluZyk6IFN0eWxlW10ge1xuICAgIHJldHVybiBbXG4gICAgICBuZXcgU3R5bGUoe1xuICAgICAgICBnZW9tZXRyeTogbmV3IFBvaW50KGNvb3JkKSxcbiAgICAgICAgaW1hZ2U6IG5ldyBDaXJjbGVTdHlsZSh7XG4gICAgICAgICAgcmFkaXVzOiAzLjUsXG4gICAgICAgICAgZmlsbDogbmV3IEZpbGwoeyBjb2xvciB9KSxcbiAgICAgICAgfSksXG4gICAgICB9KSxcbiAgICAgIG5ldyBTdHlsZSh7XG4gICAgICAgIGdlb21ldHJ5OiBuZXcgUG9pbnQoY29vcmQpLFxuICAgICAgICBpbWFnZTogbmV3IEljb24oe1xuICAgICAgICAgIHNyYzogdGhpcy5udW1iZXJCYWRnZURhdGFVcmwoaW5kZXgsIGNvbG9yKSxcbiAgICAgICAgICBhbmNob3I6IFswLjUsIDEuMzVdLFxuICAgICAgICAgIGFuY2hvclhVbml0czogJ2ZyYWN0aW9uJyxcbiAgICAgICAgICBhbmNob3JZVW5pdHM6ICdmcmFjdGlvbicsXG4gICAgICAgICAgc2NhbGU6IDEsXG4gICAgICAgIH0pLFxuICAgICAgfSksXG4gICAgXTtcbiAgfVxuXG4gIHByaXZhdGUgbnVtYmVyQmFkZ2VEYXRhVXJsKGluZGV4OiBudW1iZXIsIGNvbG9yOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHN2ZyA9XG4gICAgICBgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIyMlwiIGhlaWdodD1cIjIyXCIgdmlld0JveD1cIjAgMCAyMiAyMlwiPmAgK1xuICAgICAgYDxjaXJjbGUgY3g9XCIxMVwiIGN5PVwiMTFcIiByPVwiMTBcIiBmaWxsPVwiJHtjb2xvcn1cIi8+YCArXG4gICAgICBgPHRleHQgeD1cIjExXCIgeT1cIjE1XCIgdGV4dC1hbmNob3I9XCJtaWRkbGVcIiBmaWxsPVwiI2ZmZmZmZlwiIGAgK1xuICAgICAgYGZvbnQtc2l6ZT1cIjExXCIgZm9udC13ZWlnaHQ9XCI3MDBcIiBmb250LWZhbWlseT1cInNhbnMtc2VyaWZcIj4ke2luZGV4fTwvdGV4dD5gICtcbiAgICAgIGA8L3N2Zz5gO1xuICAgIHJldHVybiBgZGF0YTppbWFnZS9zdmcreG1sO2NoYXJzZXQ9dXRmLTgsJHtlbmNvZGVVUklDb21wb25lbnQoc3ZnKX1gO1xuICB9XG5cbiAgcHJpdmF0ZSBzZWdtZW50TGFiZWxTdHlsZShcbiAgICBhOiBudW1iZXJbXSxcbiAgICBiOiBudW1iZXJbXSxcbiAgICBjb2xvcjogc3RyaW5nLFxuICAgIGZvbnRGYW1pbHk6IHN0cmluZyxcbiAgKTogU3R5bGUge1xuICAgIGNvbnN0IG1pZDogW251bWJlciwgbnVtYmVyXSA9IFsoYVswXSArIGJbMF0pIC8gMiwgKGFbMV0gKyBiWzFdKSAvIDJdO1xuICAgIGNvbnN0IG1ldGVycyA9IGdldExlbmd0aChuZXcgTGluZVN0cmluZyhbYSwgYl0pKTtcbiAgICBsZXQgcm90YXRpb24gPSAtTWF0aC5hdGFuMihiWzFdIC0gYVsxXSwgYlswXSAtIGFbMF0pO1xuICAgIC8vIEtlZXAgbGFiZWxzIHVwcmlnaHQvcmVhZGFibGUuXG4gICAgaWYgKHJvdGF0aW9uID4gTWF0aC5QSSAvIDIgfHwgcm90YXRpb24gPCAtTWF0aC5QSSAvIDIpIHtcbiAgICAgIHJvdGF0aW9uICs9IE1hdGguUEk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBTdHlsZSh7XG4gICAgICBnZW9tZXRyeTogbmV3IFBvaW50KG1pZCksXG4gICAgICB0ZXh0OiBuZXcgVGV4dCh7XG4gICAgICAgIHRleHQ6IHRoaXMuZm9ybWF0TGVuZ3RoTGFiZWwobWV0ZXJzKSxcbiAgICAgICAgZm9udDogYDUwMCAxMnB4ICR7Zm9udEZhbWlseX1gLFxuICAgICAgICBmaWxsOiBuZXcgRmlsbCh7IGNvbG9yIH0pLFxuICAgICAgICBzdHJva2U6IG5ldyBTdHJva2Uoe1xuICAgICAgICAgIGNvbG9yOiAncmdiYSgyNTUsIDI1NSwgMjU1LCAwLjkpJyxcbiAgICAgICAgICB3aWR0aDogMyxcbiAgICAgICAgfSksXG4gICAgICAgIHJvdGF0aW9uLFxuICAgICAgICByb3RhdGVXaXRoVmlldzogdHJ1ZSxcbiAgICAgICAgdGV4dEFsaWduOiAnY2VudGVyJyxcbiAgICAgICAgdGV4dEJhc2VsaW5lOiAnbWlkZGxlJyxcbiAgICAgIH0pLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhcmVhQ2VudHJvaWRMYWJlbChcbiAgICBnZW9tZXRyeTogUG9seWdvbixcbiAgICBjb2xvcjogc3RyaW5nLFxuICAgIGZvbnRGYW1pbHk6IHN0cmluZyxcbiAgKTogU3R5bGUgfCBudWxsIHtcbiAgICBjb25zdCBpbnRlcmlvciA9IGdlb21ldHJ5LmdldEludGVyaW9yUG9pbnQoKT8uZ2V0Q29vcmRpbmF0ZXMoKTtcbiAgICBpZiAoIWludGVyaW9yKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgY29uc3Qgc3FNZXRlcnMgPSBnZXRBcmVhKGdlb21ldHJ5KTtcbiAgICByZXR1cm4gbmV3IFN0eWxlKHtcbiAgICAgIGdlb21ldHJ5OiBuZXcgUG9pbnQoaW50ZXJpb3IpLFxuICAgICAgdGV4dDogbmV3IFRleHQoe1xuICAgICAgICB0ZXh0OiB0aGlzLmZvcm1hdEFyZWFMYWJlbChzcU1ldGVycyksXG4gICAgICAgIGZvbnQ6IGA2MDAgMTJweCAke2ZvbnRGYW1pbHl9YCxcbiAgICAgICAgZmlsbDogbmV3IEZpbGwoeyBjb2xvciB9KSxcbiAgICAgICAgc3Ryb2tlOiBuZXcgU3Ryb2tlKHtcbiAgICAgICAgICBjb2xvcjogJ3JnYmEoMjU1LCAyNTUsIDI1NSwgMC45MiknLFxuICAgICAgICAgIHdpZHRoOiAzLjUsXG4gICAgICAgIH0pLFxuICAgICAgICB0ZXh0QWxpZ246ICdjZW50ZXInLFxuICAgICAgICB0ZXh0QmFzZWxpbmU6ICdtaWRkbGUnLFxuICAgICAgfSksXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGZvcm1hdExlbmd0aExhYmVsKG1ldGVyczogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBpZiAobWV0ZXJzID49IDEwMDApIHtcbiAgICAgIHJldHVybiBgJHsobWV0ZXJzIC8gMTAwMCkudG9GaXhlZCgxKX0ga21gO1xuICAgIH1cbiAgICByZXR1cm4gYCR7bWV0ZXJzLnRvRml4ZWQoMSl9IG1gO1xuICB9XG5cbiAgcHJpdmF0ZSBmb3JtYXRBcmVhTGFiZWwoc3FNZXRlcnM6IG51bWJlcik6IHN0cmluZyB7XG4gICAgaWYgKHNxTWV0ZXJzID49IDEwXzAwMCkge1xuICAgICAgcmV0dXJuIGAkeyhzcU1ldGVycyAvIDEwXzAwMCkudG9GaXhlZCgyKX0gaGFgO1xuICAgIH1cbiAgICByZXR1cm4gYCR7c3FNZXRlcnMudG9GaXhlZCgxKX0gbcKyYDtcbiAgfVxuXG4gIC8qKiBSZXNvbHZlIGEgZGVzaWduIHRva2VuIGZvciBPcGVuTGF5ZXJzIGNhbnZhcyBzdHlsZXMuICovXG4gIHByaXZhdGUgY3NzQ29sb3IoXG4gICAgdG9rZW46IHN0cmluZyxcbiAgICBmYWxsYmFjazogc3RyaW5nLFxuICAgIGFscGhhPzogbnVtYmVyLFxuICApOiBzdHJpbmcge1xuICAgIGlmICh0eXBlb2YgZG9jdW1lbnQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gYWxwaGEgIT0gbnVsbCA/IHRoaXMud2l0aEFscGhhKGZhbGxiYWNrLCBhbHBoYSkgOiBmYWxsYmFjaztcbiAgICB9XG4gICAgY29uc3QgcmF3ID0gZ2V0Q29tcHV0ZWRTdHlsZShkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpXG4gICAgICAuZ2V0UHJvcGVydHlWYWx1ZSh0b2tlbilcbiAgICAgIC50cmltKCk7XG4gICAgY29uc3QgY29sb3IgPSByYXcgfHwgZmFsbGJhY2s7XG4gICAgcmV0dXJuIGFscGhhICE9IG51bGwgPyB0aGlzLndpdGhBbHBoYShjb2xvciwgYWxwaGEpIDogY29sb3I7XG4gIH1cblxuICBwcml2YXRlIGNzc0ZvbnRGYW1pbHkoKTogc3RyaW5nIHtcbiAgICBpZiAodHlwZW9mIGRvY3VtZW50ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuICdzYW5zLXNlcmlmJztcbiAgICB9XG4gICAgY29uc3QgcmF3ID0gZ2V0Q29tcHV0ZWRTdHlsZShkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpXG4gICAgICAuZ2V0UHJvcGVydHlWYWx1ZSgnLS1nZW8tZm9udC1mYW1pbHknKVxuICAgICAgLnRyaW0oKTtcbiAgICByZXR1cm4gcmF3IHx8ICdzYW5zLXNlcmlmJztcbiAgfVxuXG4gIHByaXZhdGUgd2l0aEFscGhhKGNvbG9yOiBzdHJpbmcsIGFscGhhOiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGNvbnN0IGhleCA9IGNvbG9yLm1hdGNoKC9eIyhbMC05YS1mXXs2fSkkL2kpO1xuICAgIGlmIChoZXgpIHtcbiAgICAgIGNvbnN0IG4gPSBwYXJzZUludChoZXhbMV0sIDE2KTtcbiAgICAgIGNvbnN0IHIgPSAobiA+PiAxNikgJiAyNTU7XG4gICAgICBjb25zdCBnID0gKG4gPj4gOCkgJiAyNTU7XG4gICAgICBjb25zdCBiID0gbiAmIDI1NTtcbiAgICAgIHJldHVybiBgcmdiYSgke3J9LCAke2d9LCAke2J9LCAke2FscGhhfSlgO1xuICAgIH1cbiAgICByZXR1cm4gY29sb3I7XG4gIH1cblxuICBwcml2YXRlIGZvcm1hdFJlc3VsdChcbiAgICBtb2RlOiBFeGNsdWRlPEdlb01hcE1lYXN1cmVNb2RlLCAnbm9uZSc+LFxuICAgIGdlb21ldHJ5OiBHZW9tZXRyeSxcbiAgKTogR2VvTWFwTWVhc3VyZVJlc3VsdCB7XG4gICAgaWYgKG1vZGUgPT09ICdkaXN0YW5jZScgJiYgZ2VvbWV0cnkgaW5zdGFuY2VvZiBMaW5lU3RyaW5nKSB7XG4gICAgICBjb25zdCBtZXRlcnMgPSBnZXRMZW5ndGgoZ2VvbWV0cnkpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbW9kZSxcbiAgICAgICAgdmFsdWU6IG1ldGVycyxcbiAgICAgICAgbGFiZWw6IHRoaXMuZm9ybWF0TGVuZ3RoTGFiZWwobWV0ZXJzKSxcbiAgICAgICAgZ2VvbWV0cnksXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmIChtb2RlID09PSAnYXJlYScgJiYgZ2VvbWV0cnkgaW5zdGFuY2VvZiBQb2x5Z29uKSB7XG4gICAgICBjb25zdCBzcU1ldGVycyA9IGdldEFyZWEoZ2VvbWV0cnkpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgbW9kZSxcbiAgICAgICAgdmFsdWU6IHNxTWV0ZXJzLFxuICAgICAgICBsYWJlbDogdGhpcy5mb3JtYXRBcmVhTGFiZWwoc3FNZXRlcnMpLFxuICAgICAgICBnZW9tZXRyeSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHsgbW9kZSwgdmFsdWU6IDAsIGxhYmVsOiAnLScsIGdlb21ldHJ5IH07XG4gIH1cblxuICBwcml2YXRlIHJlbW92ZURyYXcobWFwOiBPbE1hcCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmRyYXcpIHtcbiAgICAgIG1hcC5yZW1vdmVJbnRlcmFjdGlvbih0aGlzLmRyYXcpO1xuICAgICAgdGhpcy5kcmF3ID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5yZXN1bWVJbnRlcmFjdGlvbnM/LigpO1xuICAgIHRoaXMucmVzdW1lSW50ZXJhY3Rpb25zID0gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgc2V0TWFwQ3Vyc29yKG1hcDogT2xNYXAsIGN1cnNvcjogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgIGNvbnN0IGVsID0gbWFwLmdldFRhcmdldEVsZW1lbnQoKTtcbiAgICBpZiAoIWVsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGVsLnN0eWxlLmN1cnNvciA9IGN1cnNvciA/PyAnJztcbiAgfVxuXG4gIHByaXZhdGUgdGVhcmRvd24oKTogdm9pZCB7XG4gICAgY29uc3QgbWFwID0gdGhpcy5ib3VuZE1hcCA/PyB0aGlzLmNvbnRyb2xsZXIoKT8uZ2V0TWFwKCkgPz8gbnVsbDtcbiAgICBpZiAobWFwKSB7XG4gICAgICB0aGlzLnJlbW92ZURyYXcobWFwKTtcbiAgICAgIHRoaXMuc2V0TWFwQ3Vyc29yKG1hcCwgbnVsbCk7XG4gICAgICBpZiAodGhpcy5sYXllcikge1xuICAgICAgICBtYXAucmVtb3ZlTGF5ZXIodGhpcy5sYXllcik7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuZHJhdyA9IG51bGw7XG4gICAgdGhpcy5sYXllciA9IG51bGw7XG4gICAgdGhpcy5zb3VyY2UgPSBudWxsO1xuICAgIHRoaXMuYm91bmRNYXAgPSBudWxsO1xuICB9XG59XG4iLCJAaWYgKHNob3dSZXN1bHQoKSAmJiByZXN1bHQoKTsgYXMgbWVhc3VyZWQpIHtcbiAgPGRpdiBjbGFzcz1cImdlby1tYXAtbWVhc3VyZV9fcmVzdWx0XCIgcm9sZT1cInN0YXR1c1wiPlxuICAgIDxzcGFuIGNsYXNzPVwiZ2VvLW1hcC1tZWFzdXJlX19yZXN1bHQtbGFiZWxcIj5cbiAgICAgIHt7IG1lYXN1cmVkLm1vZGUgPT09ICdkaXN0YW5jZScgPyAnS2hv4bqjbmcgY8OhY2gnIDogJ0Rp4buHbiB0w61jaCcgfX06XG4gICAgICA8c3Ryb25nPnt7IG1lYXN1cmVkLmxhYmVsIH19PC9zdHJvbmc+XG4gICAgPC9zcGFuPlxuICAgIDxidXR0b25cbiAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgY2xhc3M9XCJnZW8tbWFwLW1lYXN1cmVfX2NsZWFyXCJcbiAgICAgIChjbGljayk9XCJjbGVhcigpXCJcbiAgICA+XG4gICAgICBYw7NhXG4gICAgPC9idXR0b24+XG4gIDwvZGl2PlxufVxuXG5AaWYgKG1vZGUoKSAhPT0gJ25vbmUnKSB7XG4gIDxkaXYgY2xhc3M9XCJnZW8tbWFwLW1lYXN1cmVfX2hpbnRcIiByb2xlPVwic3RhdHVzXCI+XG4gICAge3tcbiAgICAgIG1vZGUoKSA9PT0gJ2Rpc3RhbmNlJ1xuICAgICAgICA/ICdOaOG6pXAgY8OhYyDEkWnhu4NtIMSR4buDIMSRbyBraG/huqNuZyBjw6FjaC4gTmjDoXkgxJHDunAgxJHhu4Mga+G6v3QgdGjDumMuJ1xuICAgICAgICA6ICdOaOG6pXAgY8OhYyDEkWnhu4NtIMSR4buDIMSRbyBkaeG7h24gdMOtY2guIE5ow6F5IMSRw7pwIMSR4buDIGvhur90IHRow7pjLidcbiAgICB9fVxuICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiZ2VvLW1hcC1tZWFzdXJlX19jbGVhclwiIChjbGljayk9XCJjbGVhcigpXCI+XG4gICAgICBI4buneVxuICAgIDwvYnV0dG9uPlxuICA8L2Rpdj5cbn1cbiJdfQ==
@@ -0,0 +1,94 @@
1
+ import { ChangeDetectionStrategy, Component, computed, effect, input, model, signal, ViewEncapsulation, } from '@angular/core';
2
+ import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
3
+ import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
4
+ import { GeoIconComponent } from '../../../geo-icon/geo-icon.component';
5
+ import { GeoSliderComponent } from '../../../geo-slider/geo-slider.component';
6
+ import { GEO_MAP_BASEMAP_LAYER_ID } from '../../geo-map.constants';
7
+ import * as i0 from "@angular/core";
8
+ import * as i1 from "ng-zorro-antd/dropdown";
9
+ import * as i2 from "ng-zorro-antd/tooltip";
10
+ /**
11
+ * Pick a layer and adjust opacity 0–100%.
12
+ *
13
+ * @summary Layer opacity slider for map chrome.
14
+ * @whenToUse Điều chỉnh độ trong suốt khi so sánh lớp.
15
+ * @doNotUseWhen Generic sliders outside map — use geo-slider.
16
+ */
17
+ export class GeoMapOpacityComponent {
18
+ controller = input(null);
19
+ title = input('Độ trong suốt');
20
+ layerId = model(null);
21
+ /** Opacity percent 0–100. */
22
+ opacity = model(100);
23
+ variant = input('panel');
24
+ /** When compact and no layerId, apply to first non-basemap overlay. */
25
+ applyToFirstLayer = input(true);
26
+ open = signal(false);
27
+ layerOptions = computed(() => {
28
+ const ctrl = this.controller();
29
+ if (!ctrl) {
30
+ return [];
31
+ }
32
+ return ctrl
33
+ .getLayers()
34
+ .filter((item) => item.id !== GEO_MAP_BASEMAP_LAYER_ID)
35
+ .map((item) => ({
36
+ id: item.id,
37
+ title: item.config.title || item.id,
38
+ }));
39
+ });
40
+ constructor() {
41
+ effect(() => {
42
+ const ctrl = this.controller();
43
+ const id = this.resolveTargetId();
44
+ if (!ctrl || !id) {
45
+ return;
46
+ }
47
+ const managed = ctrl.getLayers().find((item) => item.id === id);
48
+ if (!managed) {
49
+ return;
50
+ }
51
+ const pct = Math.round((managed.config.opacity ?? 1) * 100);
52
+ if (pct !== this.opacity()) {
53
+ this.opacity.set(pct);
54
+ }
55
+ });
56
+ effect(() => {
57
+ const ctrl = this.controller();
58
+ const id = this.resolveTargetId();
59
+ const pct = this.opacity();
60
+ if (!ctrl || !id) {
61
+ return;
62
+ }
63
+ ctrl.setLayerOpacity(id, Math.min(1, Math.max(0, pct / 100)));
64
+ });
65
+ }
66
+ onVisible(visible) {
67
+ this.open.set(visible);
68
+ }
69
+ selectLayer(id) {
70
+ this.layerId.set(id);
71
+ }
72
+ resolveTargetId() {
73
+ const explicit = this.layerId();
74
+ if (explicit) {
75
+ return explicit;
76
+ }
77
+ if (!this.applyToFirstLayer()) {
78
+ return null;
79
+ }
80
+ return this.layerOptions()[0]?.id ?? null;
81
+ }
82
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoMapOpacityComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
83
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: GeoMapOpacityComponent, isStandalone: true, selector: "geo-map-opacity", inputs: { controller: { classPropertyName: "controller", publicName: "controller", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, layerId: { classPropertyName: "layerId", publicName: "layerId", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, applyToFirstLayer: { classPropertyName: "applyToFirstLayer", publicName: "applyToFirstLayer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layerId: "layerIdChange", opacity: "opacityChange" }, host: { classAttribute: "geo-map-opacity-host" }, ngImport: i0, template: "@if (variant() === 'compact') {\n <button\n type=\"button\"\n class=\"geo-map-opacity__trigger\"\n nz-dropdown\n nzTrigger=\"click\"\n nzPlacement=\"bottomLeft\"\n nzOverlayClassName=\"geo-map-opacity-overlay\"\n [nzDropdownMenu]=\"menu\"\n [nzVisible]=\"open()\"\n (nzVisibleChange)=\"onVisible($event)\"\n [nz-tooltip]=\"title()\"\n nzTooltipPlacement=\"left\"\n [attr.aria-label]=\"title()\"\n [disabled]=\"!controller()\"\n >\n <geo-icon type=\"bg-colors\" size=\"md\" />\n </button>\n\n <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n <div class=\"geo-map-opacity__panel geo-map-opacity__panel--popup\">\n <div class=\"geo-map-opacity__title\">{{ title() }}</div>\n @if (layerOptions().length > 1) {\n <ul class=\"geo-map-opacity__layers\">\n @for (layer of layerOptions(); track layer.id) {\n <li>\n <button\n type=\"button\"\n class=\"geo-map-opacity__layer\"\n [class.geo-map-opacity__layer--active]=\"\n layer.id === (layerId() || layerOptions()[0].id)\n \"\n (click)=\"selectLayer(layer.id)\"\n >\n {{ layer.title }}\n </button>\n </li>\n }\n </ul>\n } @else if (layerOptions().length === 1) {\n <div class=\"geo-map-opacity__layer-name\">\n {{ layerOptions()[0].title }}\n </div>\n } @else {\n <div class=\"geo-map-opacity__empty\">Ch\u01B0a c\u00F3 l\u1EDBp \u0111\u1EC3 ch\u1EC9nh.</div>\n }\n\n <div class=\"geo-map-opacity__slider\">\n <geo-slider [(value)]=\"opacity\" [min]=\"0\" [max]=\"100\" [step]=\"1\" />\n <span class=\"geo-map-opacity__value\">{{ opacity() }}%</span>\n </div>\n </div>\n </nz-dropdown-menu>\n} @else {\n <div class=\"geo-map-opacity__panel\">\n <div class=\"geo-map-opacity__title\">{{ title() }}</div>\n @if (layerOptions().length > 1) {\n <ul class=\"geo-map-opacity__layers\">\n @for (layer of layerOptions(); track layer.id) {\n <li>\n <button\n type=\"button\"\n class=\"geo-map-opacity__layer\"\n [class.geo-map-opacity__layer--active]=\"\n layer.id === (layerId() || layerOptions()[0].id)\n \"\n (click)=\"selectLayer(layer.id)\"\n >\n {{ layer.title }}\n </button>\n </li>\n }\n </ul>\n } @else if (layerOptions().length === 1) {\n <div class=\"geo-map-opacity__layer-name\">{{ layerOptions()[0].title }}</div>\n } @else {\n <div class=\"geo-map-opacity__empty\">Ch\u01B0a c\u00F3 l\u1EDBp \u0111\u1EC3 ch\u1EC9nh.</div>\n }\n\n <div class=\"geo-map-opacity__slider\">\n <geo-slider [(value)]=\"opacity\" [min]=\"0\" [max]=\"100\" [step]=\"1\" />\n <span class=\"geo-map-opacity__value\">{{ opacity() }}%</span>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";.geo-map-opacity-host{display:block}.geo-map-opacity__trigger{border:1px solid var(--geo-color-border-default);border-radius:var(--geo-radius-lg);background:var(--geo-color-surface-elevated);box-shadow:var(--geo-shadow-sm);display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:40px;min-height:40px;border:0;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-700);font:inherit;font-size:var(--geo-font-size-body-small);font-weight:var(--geo-font-weight-medium);line-height:1;cursor:pointer;transition:background-color .15s ease,color .15s ease,transform .1s ease;width:48px;min-height:48px;padding:0}.geo-map-opacity__trigger:hover:not(:disabled){background:var(--geo-color-primary-soft-hover);color:var(--geo-color-primary-default)}.geo-map-opacity__trigger:active:not(:disabled){transform:scale(.98)}.geo-map-opacity__trigger:disabled{opacity:.45;cursor:not-allowed}.geo-map-opacity__trigger--active,.geo-map-opacity__trigger--checked{background:var(--geo-color-primary-soft-active);color:var(--geo-color-primary-default)}.geo-map-opacity__trigger--icon-only{width:40px;padding:0}.geo-map-opacity-overlay .ant-dropdown-menu{padding:0;border:0;background:transparent;box-shadow:none}.geo-map-opacity__panel{border:1px solid var(--geo-color-border-default);border-radius:var(--geo-radius-lg);background:var(--geo-color-surface-elevated);box-shadow:var(--geo-shadow-sm);min-width:220px;padding:10px 12px}.geo-map-opacity__panel--popup{box-shadow:var(--geo-shadow-md)}.geo-map-opacity__title{margin-bottom:8px;font-size:var(--geo-font-size-body-small);font-weight:var(--geo-font-weight-semibold);color:var(--geo-color-neutral-900)}.geo-map-opacity__layers{display:flex;flex-direction:column;gap:4px;margin:0 0 10px;padding:0;list-style:none}.geo-map-opacity__layer{width:100%;padding:6px 8px;border:0;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-800);font:inherit;font-size:var(--geo-font-size-body-small);text-align:left;cursor:pointer}.geo-map-opacity__layer:hover{background:var(--geo-color-primary-soft-hover);color:var(--geo-color-primary-default)}.geo-map-opacity__layer--active{background:var(--geo-color-primary-soft-active);color:var(--geo-color-primary-default);font-weight:var(--geo-font-weight-semibold)}.geo-map-opacity__layer-name,.geo-map-opacity__empty{margin-bottom:8px;font-size:var(--geo-font-size-caption);color:var(--geo-color-neutral-600)}.geo-map-opacity__slider{display:flex;align-items:center;gap:10px}.geo-map-opacity__slider geo-slider{flex:1;min-width:0}.geo-map-opacity__value{flex-shrink:0;min-width:40px;font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-semibold);color:var(--geo-color-neutral-700);text-align:right}\n"], dependencies: [{ kind: "ngmodule", type: NzDropDownModule }, { kind: "directive", type: i1.NzDropDownDirective, selector: "[nz-dropdown]", inputs: ["nzDropdownMenu", "nzTrigger", "nzMatchWidthElement", "nzBackdrop", "nzClickHide", "nzDisabled", "nzVisible", "nzOverlayClassName", "nzOverlayStyle", "nzPlacement"], outputs: ["nzVisibleChange"], exportAs: ["nzDropdown"] }, { kind: "component", type: i1.NzDropdownMenuComponent, selector: "nz-dropdown-menu", exportAs: ["nzDropdownMenu"] }, { kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i2.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }, { kind: "component", type: GeoIconComponent, selector: "geo-icon", inputs: ["type", "theme", "spin", "size", "color"] }, { kind: "component", type: GeoSliderComponent, selector: "geo-slider", inputs: ["value", "min", "max", "step", "disabled", "tipFormatter"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
84
+ }
85
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: GeoMapOpacityComponent, decorators: [{
86
+ type: Component,
87
+ args: [{ selector: 'geo-map-opacity', standalone: true, imports: [
88
+ NzDropDownModule,
89
+ NzToolTipModule,
90
+ GeoIconComponent,
91
+ GeoSliderComponent,
92
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'geo-map-opacity-host' }, template: "@if (variant() === 'compact') {\n <button\n type=\"button\"\n class=\"geo-map-opacity__trigger\"\n nz-dropdown\n nzTrigger=\"click\"\n nzPlacement=\"bottomLeft\"\n nzOverlayClassName=\"geo-map-opacity-overlay\"\n [nzDropdownMenu]=\"menu\"\n [nzVisible]=\"open()\"\n (nzVisibleChange)=\"onVisible($event)\"\n [nz-tooltip]=\"title()\"\n nzTooltipPlacement=\"left\"\n [attr.aria-label]=\"title()\"\n [disabled]=\"!controller()\"\n >\n <geo-icon type=\"bg-colors\" size=\"md\" />\n </button>\n\n <nz-dropdown-menu #menu=\"nzDropdownMenu\">\n <div class=\"geo-map-opacity__panel geo-map-opacity__panel--popup\">\n <div class=\"geo-map-opacity__title\">{{ title() }}</div>\n @if (layerOptions().length > 1) {\n <ul class=\"geo-map-opacity__layers\">\n @for (layer of layerOptions(); track layer.id) {\n <li>\n <button\n type=\"button\"\n class=\"geo-map-opacity__layer\"\n [class.geo-map-opacity__layer--active]=\"\n layer.id === (layerId() || layerOptions()[0].id)\n \"\n (click)=\"selectLayer(layer.id)\"\n >\n {{ layer.title }}\n </button>\n </li>\n }\n </ul>\n } @else if (layerOptions().length === 1) {\n <div class=\"geo-map-opacity__layer-name\">\n {{ layerOptions()[0].title }}\n </div>\n } @else {\n <div class=\"geo-map-opacity__empty\">Ch\u01B0a c\u00F3 l\u1EDBp \u0111\u1EC3 ch\u1EC9nh.</div>\n }\n\n <div class=\"geo-map-opacity__slider\">\n <geo-slider [(value)]=\"opacity\" [min]=\"0\" [max]=\"100\" [step]=\"1\" />\n <span class=\"geo-map-opacity__value\">{{ opacity() }}%</span>\n </div>\n </div>\n </nz-dropdown-menu>\n} @else {\n <div class=\"geo-map-opacity__panel\">\n <div class=\"geo-map-opacity__title\">{{ title() }}</div>\n @if (layerOptions().length > 1) {\n <ul class=\"geo-map-opacity__layers\">\n @for (layer of layerOptions(); track layer.id) {\n <li>\n <button\n type=\"button\"\n class=\"geo-map-opacity__layer\"\n [class.geo-map-opacity__layer--active]=\"\n layer.id === (layerId() || layerOptions()[0].id)\n \"\n (click)=\"selectLayer(layer.id)\"\n >\n {{ layer.title }}\n </button>\n </li>\n }\n </ul>\n } @else if (layerOptions().length === 1) {\n <div class=\"geo-map-opacity__layer-name\">{{ layerOptions()[0].title }}</div>\n } @else {\n <div class=\"geo-map-opacity__empty\">Ch\u01B0a c\u00F3 l\u1EDBp \u0111\u1EC3 ch\u1EC9nh.</div>\n }\n\n <div class=\"geo-map-opacity__slider\">\n <geo-slider [(value)]=\"opacity\" [min]=\"0\" [max]=\"100\" [step]=\"1\" />\n <span class=\"geo-map-opacity__value\">{{ opacity() }}%</span>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";.geo-map-opacity-host{display:block}.geo-map-opacity__trigger{border:1px solid var(--geo-color-border-default);border-radius:var(--geo-radius-lg);background:var(--geo-color-surface-elevated);box-shadow:var(--geo-shadow-sm);display:inline-flex;align-items:center;justify-content:center;gap:6px;min-width:40px;min-height:40px;border:0;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-700);font:inherit;font-size:var(--geo-font-size-body-small);font-weight:var(--geo-font-weight-medium);line-height:1;cursor:pointer;transition:background-color .15s ease,color .15s ease,transform .1s ease;width:48px;min-height:48px;padding:0}.geo-map-opacity__trigger:hover:not(:disabled){background:var(--geo-color-primary-soft-hover);color:var(--geo-color-primary-default)}.geo-map-opacity__trigger:active:not(:disabled){transform:scale(.98)}.geo-map-opacity__trigger:disabled{opacity:.45;cursor:not-allowed}.geo-map-opacity__trigger--active,.geo-map-opacity__trigger--checked{background:var(--geo-color-primary-soft-active);color:var(--geo-color-primary-default)}.geo-map-opacity__trigger--icon-only{width:40px;padding:0}.geo-map-opacity-overlay .ant-dropdown-menu{padding:0;border:0;background:transparent;box-shadow:none}.geo-map-opacity__panel{border:1px solid var(--geo-color-border-default);border-radius:var(--geo-radius-lg);background:var(--geo-color-surface-elevated);box-shadow:var(--geo-shadow-sm);min-width:220px;padding:10px 12px}.geo-map-opacity__panel--popup{box-shadow:var(--geo-shadow-md)}.geo-map-opacity__title{margin-bottom:8px;font-size:var(--geo-font-size-body-small);font-weight:var(--geo-font-weight-semibold);color:var(--geo-color-neutral-900)}.geo-map-opacity__layers{display:flex;flex-direction:column;gap:4px;margin:0 0 10px;padding:0;list-style:none}.geo-map-opacity__layer{width:100%;padding:6px 8px;border:0;border-radius:var(--geo-radius);background:transparent;color:var(--geo-color-neutral-800);font:inherit;font-size:var(--geo-font-size-body-small);text-align:left;cursor:pointer}.geo-map-opacity__layer:hover{background:var(--geo-color-primary-soft-hover);color:var(--geo-color-primary-default)}.geo-map-opacity__layer--active{background:var(--geo-color-primary-soft-active);color:var(--geo-color-primary-default);font-weight:var(--geo-font-weight-semibold)}.geo-map-opacity__layer-name,.geo-map-opacity__empty{margin-bottom:8px;font-size:var(--geo-font-size-caption);color:var(--geo-color-neutral-600)}.geo-map-opacity__slider{display:flex;align-items:center;gap:10px}.geo-map-opacity__slider geo-slider{flex:1;min-width:0}.geo-map-opacity__value{flex-shrink:0;min-width:40px;font-size:var(--geo-font-size-caption);font-weight:var(--geo-font-weight-semibold);color:var(--geo-color-neutral-700);text-align:right}\n"] }]
93
+ }], ctorParameters: () => [] });
94
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VvLW1hcC1vcGFjaXR5LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2dlby11aS9zcmMvbGliL2ZpZ21hL2dlby1tYXAvY2hyb21lL2dlby1tYXAtb3BhY2l0eS9nZW8tbWFwLW9wYWNpdHkuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZ2VvLXVpL3NyYy9saWIvZmlnbWEvZ2VvLW1hcC9jaHJvbWUvZ2VvLW1hcC1vcGFjaXR5L2dlby1tYXAtb3BhY2l0eS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsdUJBQXVCLEVBQ3ZCLFNBQVMsRUFDVCxRQUFRLEVBQ1IsTUFBTSxFQUNOLEtBQUssRUFDTCxLQUFLLEVBQ0wsTUFBTSxFQUNOLGlCQUFpQixHQUNsQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDeEUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMENBQTBDLENBQUM7QUFDOUUsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0seUJBQXlCLENBQUM7Ozs7QUFHbkU7Ozs7OztHQU1HO0FBZ0JILE1BQU0sT0FBTyxzQkFBc0I7SUFDeEIsVUFBVSxHQUFHLEtBQUssQ0FBMEIsSUFBSSxDQUFDLENBQUM7SUFDbEQsS0FBSyxHQUFHLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUMvQixPQUFPLEdBQUcsS0FBSyxDQUFnQixJQUFJLENBQUMsQ0FBQztJQUM5Qyw2QkFBNkI7SUFDcEIsT0FBTyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNy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TyxRQUFRLENBQUM7UUFDbEIsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDO1lBQzlCLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxJQUFJLENBQUM7SUFDNUMsQ0FBQzt3R0F2RVUsc0JBQXNCOzRGQUF0QixzQkFBc0IsKzlCQ3ZDbkMsazlGQXFGQSw2eEZEekRJLGdCQUFnQiwwY0FDaEIsZUFBZSx5ZkFDZixnQkFBZ0IseUdBQ2hCLGtCQUFrQjs7NEZBUVQsc0JBQXNCO2tCQWZsQyxTQUFTOytCQUNFLGlCQUFpQixjQUNmLElBQUksV0FDUDt3QkFDUCxnQkFBZ0I7d0JBQ2hCLGVBQWU7d0JBQ2YsZ0JBQWdCO3dCQUNoQixrQkFBa0I7cUJBQ25CLG1CQUdnQix1QkFBdUIsQ0FBQyxNQUFNLGlCQUNoQyxpQkFBaUIsQ0FBQyxJQUFJLFFBQy9CLEVBQUUsS0FBSyxFQUFFLHNCQUFzQixFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENvbXBvbmVudCxcbiAgY29tcHV0ZWQsXG4gIGVmZmVjdCxcbiAgaW5wdXQsXG4gIG1vZGVsLFxuICBzaWduYWwsXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE56RHJvcERvd25Nb2R1bGUgfSBmcm9tICduZy16b3Jyby1hbnRkL2Ryb3Bkb3duJztcbmltcG9ydCB7IE56VG9vbFRpcE1vZHVsZSB9IGZyb20gJ25nLXpvcnJvLWFudGQvdG9vbHRpcCc7XG5pbXBvcnQgeyBHZW9JY29uQ29tcG9uZW50IH0gZnJvbSAnLi4vLi4vLi4vZ2VvLWljb24vZ2VvLWljb24uY29tcG9uZW50JztcbmltcG9ydCB7IEdlb1NsaWRlckNvbXBvbmVudCB9IGZyb20gJy4uLy4uLy4uL2dlby1zbGlkZXIvZ2VvLXNsaWRlci5jb21wb25lbnQnO1xuaW1wb3J0IHsgR0VPX01BUF9CQVNFTUFQX0xBWUVSX0lEIH0gZnJvbSAnLi4vLi4vZ2VvLW1hcC5jb25zdGFudHMnO1xuaW1wb3J0IHsgR2VvTWFwQ29udHJvbGxlciB9IGZyb20gJy4uLy4uL2dlby1tYXAuY29udHJvbGxlcic7XG5cbi8qKlxuICogUGljayBhIGxheWVyIGFuZCBhZGp1c3Qgb3BhY2l0eSAw4oCTMTAwJS5cbiAqXG4gKiBAc3VtbWFyeSBMYXllciBvcGFjaXR5IHNsaWRlciBmb3IgbWFwIGNocm9tZS5cbiAqIEB3aGVuVG9Vc2UgxJBp4buBdSBjaOG7iW5oIMSR4buZIHRyb25nIHN14buRdCBraGkgc28gc8OhbmggbOG7m3AuXG4gKiBAZG9Ob3RVc2VXaGVuIEdlbmVyaWMgc2xpZGVycyBvdXRzaWRlIG1hcCDigJQgdXNlIGdlby1zbGlkZXIuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2dlby1tYXAtb3BhY2l0eScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtcbiAgICBOekRyb3BEb3duTW9kdWxlLFxuICAgIE56VG9vbFRpcE1vZHVsZSxcbiAgICBHZW9JY29uQ29tcG9uZW50LFxuICAgIEdlb1NsaWRlckNvbXBvbmVudCxcbiAgXSxcbiAgdGVtcGxhdGVVcmw6ICcuL2dlby1tYXAtb3BhY2l0eS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsOiAnLi9nZW8tbWFwLW9wYWNpdHkuY29tcG9uZW50LnNjc3MnLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgZW5jYXBzdWxhdGlvbjogVmlld0VuY2Fwc3VsYXRpb24uTm9uZSxcbiAgaG9zdDogeyBjbGFzczogJ2dlby1tYXAtb3BhY2l0eS1ob3N0JyB9LFxufSlcbmV4cG9ydCBjbGFzcyBHZW9NYXBPcGFjaXR5Q29tcG9uZW50IHtcbiAgcmVhZG9ubHkgY29udHJvbGxlciA9IGlucHV0PEdlb01hcENvbnRyb2xsZXIgfCBudWxsPihudWxsKTtcbiAgcmVhZG9ubHkgdGl0bGUgPSBpbnB1dCgnxJDhu5kgdHJvbmcgc3Xhu5F0Jyk7XG4gIHJlYWRvbmx5IGxheWVySWQgPSBtb2RlbDxzdHJpbmcgfCBudWxsPihudWxsKTtcbiAgLyoqIE9wYWNpdHkgcGVyY2VudCAw4oCTMTAwLiAqL1xuICByZWFkb25seSBvcGFjaXR5ID0gbW9kZWwoMTAwKTtcbiAgcmVhZG9ubHkgdmFyaWFudCA9IGlucHV0PCdwYW5lbCcgfCAnY29tcGFjdCc+KCdwYW5lbCcpO1xuICAvKiogV2hlbiBjb21wYWN0IGFuZCBubyBsYXllcklkLCBhcHBseSB0byBmaXJzdCBub24tYmFzZW1hcCBvdmVybGF5LiAqL1xuICByZWFkb25seSBhcHBseVRvRmlyc3RMYXllciA9IGlucHV0KHRydWUpO1xuXG4gIHJlYWRvbmx5IG9wZW4gPSBzaWduYWwoZmFsc2UpO1xuXG4gIHJlYWRvbmx5IGxheWVyT3B0aW9ucyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICBjb25zdCBjdHJsID0gdGhpcy5jb250cm9sbGVyKCk7XG4gICAgaWYgKCFjdHJsKSB7XG4gICAgICByZXR1cm4gW10gYXMgQXJyYXk8eyBpZDogc3RyaW5nOyB0aXRsZTogc3RyaW5nIH0+O1xuICAgIH1cbiAgICByZXR1cm4gY3RybFxuICAgICAgLmdldExheWVycygpXG4gICAgICAuZmlsdGVyKChpdGVtKSA9PiBpdGVtLmlkICE9PSBHRU9fTUFQX0JBU0VNQVBfTEFZRVJfSUQpXG4gICAgICAubWFwKChpdGVtKSA9PiAoe1xuICAgICAgICBpZDogaXRlbS5pZCxcbiAgICAgICAgdGl0bGU6IGl0ZW0uY29uZmlnLnRpdGxlIHx8IGl0ZW0uaWQsXG4gICAgICB9KSk7XG4gIH0pO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIGVmZmVjdCgoKSA9PiB7XG4gICAgICBjb25zdCBjdHJsID0gdGhpcy5jb250cm9sbGVyKCk7XG4gICAgICBjb25zdCBpZCA9IHRoaXMucmVzb2x2ZVRhcmdldElkKCk7XG4gICAgICBpZiAoIWN0cmwgfHwgIWlkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGNvbnN0IG1hbmFnZWQgPSBjdHJsLmdldExheWVycygpLmZpbmQoKGl0ZW0pID0+IGl0ZW0uaWQgPT09IGlkKTtcbiAgICAgIGlmICghbWFuYWdlZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCBwY3QgPSBNYXRoLnJvdW5kKChtYW5hZ2VkLmNvbmZpZy5vcGFjaXR5ID8/IDEpICogMTAwKTtcbiAgICAgIGlmIChwY3QgIT09IHRoaXMub3BhY2l0eSgpKSB7XG4gICAgICAgIHRoaXMub3BhY2l0eS5zZXQocGN0KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGVmZmVjdCgoKSA9PiB7XG4gICAgICBjb25zdCBjdHJsID0gdGhpcy5jb250cm9sbGVyKCk7XG4gICAgICBjb25zdCBpZCA9IHRoaXMucmVzb2x2ZVRhcmdldElkKCk7XG4gICAgICBjb25zdCBwY3QgPSB0aGlzLm9wYWNpdHkoKTtcbiAgICAgIGlmICghY3RybCB8fCAhaWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgY3RybC5zZXRMYXllck9wYWNpdHkoaWQsIE1hdGgubWluKDEsIE1hdGgubWF4KDAsIHBjdCAvIDEwMCkpKTtcbiAgICB9KTtcbiAgfVxuXG4gIG9uVmlzaWJsZSh2aXNpYmxlOiBib29sZWFuKTogdm9pZCB7XG4gICAgdGhpcy5vcGVuLnNldCh2aXNpYmxlKTtcbiAgfVxuXG4gIHNlbGVjdExheWVyKGlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmxheWVySWQuc2V0KGlkKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzb2x2ZVRhcmdldElkKCk6IHN0cmluZyB8IG51bGwge1xuICAgIGNvbnN0IGV4cGxpY2l0ID0gdGhpcy5sYXllcklkKCk7XG4gICAgaWYgKGV4cGxpY2l0KSB7XG4gICAgICByZXR1cm4gZXhwbGljaXQ7XG4gICAgfVxuICAgIGlmICghdGhpcy5hcHBseVRvRmlyc3RMYXllcigpKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMubGF5ZXJPcHRpb25zKClbMF0/LmlkID8/IG51bGw7XG4gIH1cbn1cbiIsIkBpZiAodmFyaWFudCgpID09PSAnY29tcGFjdCcpIHtcbiAgPGJ1dHRvblxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIGNsYXNzPVwiZ2VvLW1hcC1vcGFjaXR5X190cmlnZ2VyXCJcbiAgICBuei1kcm9wZG93blxuICAgIG56VHJpZ2dlcj1cImNsaWNrXCJcbiAgICBuelBsYWNlbWVudD1cImJvdHRvbUxlZnRcIlxuICAgIG56T3ZlcmxheUNsYXNzTmFtZT1cImdlby1tYXAtb3BhY2l0eS1vdmVybGF5XCJcbiAgICBbbnpEcm9wZG93bk1lbnVdPVwibWVudVwiXG4gICAgW256VmlzaWJsZV09XCJvcGVuKClcIlxuICAgIChuelZpc2libGVDaGFuZ2UpPVwib25WaXNpYmxlKCRldmVudClcIlxuICAgIFtuei10b29sdGlwXT1cInRpdGxlKClcIlxuICAgIG56VG9vbHRpcFBsYWNlbWVudD1cImxlZnRcIlxuICAgIFthdHRyLmFyaWEtbGFiZWxdPVwidGl0bGUoKVwiXG4gICAgW2Rpc2FibGVkXT1cIiFjb250cm9sbGVyKClcIlxuICA+XG4gICAgPGdlby1pY29uIHR5cGU9XCJiZy1jb2xvcnNcIiBzaXplPVwibWRcIiAvPlxuICA8L2J1dHRvbj5cblxuICA8bnotZHJvcGRvd24tbWVudSAjbWVudT1cIm56RHJvcGRvd25NZW51XCI+XG4gICAgPGRpdiBjbGFzcz1cImdlby1tYXAtb3BhY2l0eV9fcGFuZWwgZ2VvLW1hcC1vcGFjaXR5X19wYW5lbC0tcG9wdXBcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJnZW8tbWFwLW9wYWNpdHlfX3RpdGxlXCI+e3sgdGl0bGUoKSB9fTwvZGl2PlxuICAgICAgQGlmIChsYXllck9wdGlvbnMoKS5sZW5ndGggPiAxKSB7XG4gICAgICAgIDx1bCBjbGFzcz1cImdlby1tYXAtb3BhY2l0eV9fbGF5ZXJzXCI+XG4gICAgICAgICAgQGZvciAobGF5ZXIgb2YgbGF5ZXJPcHRpb25zKCk7IHRyYWNrIGxheWVyLmlkKSB7XG4gICAgICAgICAgICA8bGk+XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImdlby1tYXAtb3BhY2l0eV9fbGF5ZXJcIlxuICAgICAgICAgICAgICAgIFtjbGFzcy5nZW8tbWFwLW9wYWNpdHlfX2xheWVyLS1hY3RpdmVdPVwiXG4gICAgICAgICAgICAgICAgICBsYXllci5pZCA9PT0gKGxheWVySWQoKSB8fCBsYXllck9wdGlvbnMoKVswXS5pZClcbiAgICAgICAgICAgICAgICBcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJzZWxlY3RMYXllcihsYXllci5pZClcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAge3sgbGF5ZXIudGl0bGUgfX1cbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8L2xpPlxuICAgICAgICAgIH1cbiAgICAgICAgPC91bD5cbiAgICAgIH0gQGVsc2UgaWYgKGxheWVyT3B0aW9ucygpLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICA8ZGl2IGNsYXNzPVwiZ2VvLW1hcC1vcGFjaXR5X19sYXllci1uYW1lXCI+XG4gICAgICAgICAge3sgbGF5ZXJPcHRpb25zKClbMF0udGl0bGUgfX1cbiAgICAgICAgPC9kaXY+XG4gICAgICB9IEBlbHNlIHtcbiAgICAgICAgPGRpdiBjbGFzcz1cImdlby1tYXAtb3BhY2l0eV9fZW1wdHlcIj5DaMawYSBjw7MgbOG7m3AgxJHhu4MgY2jhu4luaC48L2Rpdj5cbiAgICAgIH1cblxuICAgICAgPGRpdiBjbGFzcz1cImdlby1tYXAtb3BhY2l0eV9fc2xpZGVyXCI+XG4gICAgICAgIDxnZW8tc2xpZGVyIFsodmFsdWUpXT1cIm9wYWNpdHlcIiBbbWluXT1cIjBcIiBbbWF4XT1cIjEwMFwiIFtzdGVwXT1cIjFcIiAvPlxuICAgICAgICA8c3BhbiBjbGFzcz1cImdlby1tYXAtb3BhY2l0eV9fdmFsdWVcIj57eyBvcGFjaXR5KCkgfX0lPC9zcGFuPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvbnotZHJvcGRvd24tbWVudT5cbn0gQGVsc2Uge1xuICA8ZGl2IGNsYXNzPVwiZ2VvLW1hcC1vcGFjaXR5X19wYW5lbFwiPlxuICAgIDxkaXYgY2xhc3M9XCJnZW8tbWFwLW9wYWNpdHlfX3RpdGxlXCI+e3sgdGl0bGUoKSB9fTwvZGl2PlxuICAgIEBpZiAobGF5ZXJPcHRpb25zKCkubGVuZ3RoID4gMSkge1xuICAgICAgPHVsIGNsYXNzPVwiZ2VvLW1hcC1vcGFjaXR5X19sYXllcnNcIj5cbiAgICAgICAgQGZvciAobGF5ZXIgb2YgbGF5ZXJPcHRpb25zKCk7IHRyYWNrIGxheWVyLmlkKSB7XG4gICAgICAgICAgPGxpPlxuICAgICAgICAgICAgPGJ1dHRvblxuICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJnZW8tbWFwLW9wYWNpdHlfX2xheWVyXCJcbiAgICAgICAgICAgICAgW2NsYXNzLmdlby1tYXAtb3BhY2l0eV9fbGF5ZXItLWFjdGl2ZV09XCJcbiAgICAgICAgICAgICAgICBsYXllci5pZCA9PT0gKGxheWVySWQoKSB8fCBsYXllck9wdGlvbnMoKVswXS5pZClcbiAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInNlbGVjdExheWVyKGxheWVyLmlkKVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIHt7IGxheWVyLnRpdGxlIH19XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICA8L2xpPlxuICAgICAgICB9XG4gICAgICA8L3VsPlxuICAgIH0gQGVsc2UgaWYgKGxheWVyT3B0aW9ucygpLmxlbmd0aCA9PT0gMSkge1xuICAgICAgPGRpdiBjbGFzcz1cImdlby1tYXAtb3BhY2l0eV9fbGF5ZXItbmFtZVwiPnt7IGxheWVyT3B0aW9ucygpWzBdLnRpdGxlIH19PC9kaXY+XG4gICAgfSBAZWxzZSB7XG4gICAgICA8ZGl2IGNsYXNzPVwiZ2VvLW1hcC1vcGFjaXR5X19lbXB0eVwiPkNoxrBhIGPDsyBs4bubcCDEkeG7gyBjaOG7iW5oLjwvZGl2PlxuICAgIH1cblxuICAgIDxkaXYgY2xhc3M9XCJnZW8tbWFwLW9wYWNpdHlfX3NsaWRlclwiPlxuICAgICAgPGdlby1zbGlkZXIgWyh2YWx1ZSldPVwib3BhY2l0eVwiIFttaW5dPVwiMFwiIFttYXhdPVwiMTAwXCIgW3N0ZXBdPVwiMVwiIC8+XG4gICAgICA8c3BhbiBjbGFzcz1cImdlby1tYXAtb3BhY2l0eV9fdmFsdWVcIj57eyBvcGFjaXR5KCkgfX0lPC9zcGFuPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbn1cbiJdfQ==