@kalisio/kdk 2.2.2 → 2.3.0

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 (386) hide show
  1. package/.eslintignore +1 -0
  2. package/.github/workflows/main.yaml +67 -0
  3. package/.gitmodules +3 -0
  4. package/README.md +1 -2
  5. package/core/api/hooks/hooks.query.js +15 -2
  6. package/core/api/marshall.js +35 -4
  7. package/core/client/api.js +1 -1
  8. package/core/client/components/KActivity.vue +73 -0
  9. package/core/client/components/KContent.vue +1 -1
  10. package/core/client/components/KSponsor.vue +2 -13
  11. package/core/client/components/account/KDeleteAccountManager.vue +1 -1
  12. package/core/client/components/account/KPasswordManager.vue +1 -1
  13. package/core/client/components/action/KAction.vue +294 -0
  14. package/core/client/components/action/KBugReportAction.vue +37 -0
  15. package/core/client/components/action/index.js +7 -0
  16. package/core/client/components/app/KAbout.vue +16 -63
  17. package/core/client/components/app/KPlatform.vue +1 -1
  18. package/core/client/components/app/KSettings.vue +14 -14
  19. package/core/client/components/app/KTour.vue +6 -8
  20. package/core/client/components/app/KWelcome.vue +1 -1
  21. package/core/client/components/app/index.js +4 -0
  22. package/core/client/components/chart/KDataTable.vue +40 -25
  23. package/core/client/components/chart/KTimeSeriesChart.vue +20 -12
  24. package/core/client/components/collection/KCard.vue +1 -1
  25. package/core/client/components/collection/KColumn.vue +1 -1
  26. package/core/client/components/collection/KFilter.vue +6 -1
  27. package/core/client/components/document/KDocument.vue +83 -0
  28. package/core/client/components/document/KHtml.vue +23 -0
  29. package/core/client/components/document/KMarkdown.vue +37 -0
  30. package/core/client/components/document/index.js +9 -0
  31. package/core/client/components/form/KForm.vue +5 -1
  32. package/core/client/components/form/KSelectField.vue +1 -1
  33. package/core/client/components/index.js +1 -4
  34. package/core/client/components/input/KOptionsChooser.vue +1 -1
  35. package/core/client/components/layout/KFab.vue +1 -1
  36. package/core/client/components/layout/KPage.vue +3 -2
  37. package/core/client/components/layout/KWindow.vue +1 -1
  38. package/core/client/components/media/KColorScale.vue +16 -6
  39. package/core/client/components/screen/KLoginScreen.vue +1 -1
  40. package/core/client/components/screen/KRegisterScreen.vue +1 -1
  41. package/core/client/components/team/KAddMember.vue +7 -7
  42. package/core/client/components/team/KGroupCard.vue +1 -1
  43. package/core/client/components/team/KMemberFilter.vue +1 -1
  44. package/core/client/components/team/KTagCard.vue +1 -1
  45. package/core/client/components/time/KRelativeTimeRanges.vue +1 -1
  46. package/core/client/components/time/KTimeControl.vue +1 -0
  47. package/core/client/components/tool/KExportTool.vue +1 -1
  48. package/core/client/composables/collection.js +1 -1
  49. package/core/client/composables/index.js +1 -0
  50. package/core/client/composables/layout.js +50 -0
  51. package/core/client/composables/session.js +6 -0
  52. package/core/client/filter.js +9 -6
  53. package/core/client/guards.js +29 -6
  54. package/core/client/i18n/core_en.json +1 -1
  55. package/core/client/i18n/core_fr.json +1 -1
  56. package/core/client/i18n.js +14 -0
  57. package/core/client/layout.js +25 -14
  58. package/core/client/mixins/mixin.base-activity.js +16 -0
  59. package/core/client/services/index.js +27 -26
  60. package/core/client/services/local-settings.service.js +2 -3
  61. package/core/client/units.js +6 -1
  62. package/core/client/utils/index.js +3 -0
  63. package/core/client/utils/utils.actions.js +93 -0
  64. package/core/client/utils/utils.colors.js +1 -1
  65. package/core/client/utils/utils.data.js +22 -0
  66. package/core/client/utils/utils.shapes.js +16 -6
  67. package/coverage/base.css +224 -0
  68. package/coverage/block-navigation.js +87 -0
  69. package/coverage/core/api/application.js.html +1870 -0
  70. package/coverage/core/api/authentication.js.html +742 -0
  71. package/coverage/core/api/db.js.html +778 -0
  72. package/coverage/core/api/hooks/hooks.authentication.js.html +313 -0
  73. package/coverage/core/api/hooks/hooks.authorisations.js.html +1243 -0
  74. package/coverage/core/api/hooks/hooks.groups.js.html +229 -0
  75. package/coverage/core/api/hooks/hooks.logger.js.html +163 -0
  76. package/coverage/core/api/hooks/hooks.model.js.html +955 -0
  77. package/coverage/core/api/hooks/hooks.organisations.js.html +541 -0
  78. package/coverage/core/api/hooks/hooks.push.js.html +253 -0
  79. package/coverage/core/api/hooks/hooks.query.js.html +862 -0
  80. package/coverage/core/api/hooks/hooks.schemas.js.html +304 -0
  81. package/coverage/core/api/hooks/hooks.service.js.html +319 -0
  82. package/coverage/core/api/hooks/hooks.storage.js.html +193 -0
  83. package/coverage/core/api/hooks/hooks.users.js.html +868 -0
  84. package/coverage/core/api/hooks/index.html +296 -0
  85. package/coverage/core/api/hooks/index.js.html +121 -0
  86. package/coverage/core/api/index.html +191 -0
  87. package/coverage/core/api/index.js.html +148 -0
  88. package/coverage/core/api/marshall.js.html +448 -0
  89. package/coverage/core/api/models/groups.model.mongodb.js.html +109 -0
  90. package/coverage/core/api/models/index.html +161 -0
  91. package/coverage/core/api/models/organisations.model.mongodb.js.html +94 -0
  92. package/coverage/core/api/models/tags.model.mongodb.js.html +115 -0
  93. package/coverage/core/api/models/users.model.mongodb.js.html +115 -0
  94. package/coverage/core/api/services/account/account.hooks.js.html +208 -0
  95. package/coverage/core/api/services/account/account.service.js.html +436 -0
  96. package/coverage/core/api/services/account/index.html +131 -0
  97. package/coverage/core/api/services/authorisations/authorisations.hooks.js.html +184 -0
  98. package/coverage/core/api/services/authorisations/authorisations.service.js.html +502 -0
  99. package/coverage/core/api/services/authorisations/index.html +131 -0
  100. package/coverage/core/api/services/databases/databases.hooks.js.html +193 -0
  101. package/coverage/core/api/services/databases/databases.service.js.html +100 -0
  102. package/coverage/core/api/services/databases/index.html +131 -0
  103. package/coverage/core/api/services/groups/groups.hooks.js.html +178 -0
  104. package/coverage/core/api/services/groups/index.html +116 -0
  105. package/coverage/core/api/services/import-export/import-export.hooks.js.html +184 -0
  106. package/coverage/core/api/services/import-export/import-export.service.js.html +118 -0
  107. package/coverage/core/api/services/import-export/index.html +131 -0
  108. package/coverage/core/api/services/index.html +116 -0
  109. package/coverage/core/api/services/index.js.html +499 -0
  110. package/coverage/core/api/services/mailer/index.html +131 -0
  111. package/coverage/core/api/services/mailer/mailer.hooks.js.html +190 -0
  112. package/coverage/core/api/services/mailer/mailer.service.js.html +118 -0
  113. package/coverage/core/api/services/organisations/index.html +131 -0
  114. package/coverage/core/api/services/organisations/organisations.hooks.js.html +178 -0
  115. package/coverage/core/api/services/organisations/organisations.service.js.html +343 -0
  116. package/coverage/core/api/services/push/index.html +131 -0
  117. package/coverage/core/api/services/push/push.hooks.js.html +190 -0
  118. package/coverage/core/api/services/push/push.service.js.html +121 -0
  119. package/coverage/core/api/services/storage/index.html +131 -0
  120. package/coverage/core/api/services/storage/storage.hooks.js.html +190 -0
  121. package/coverage/core/api/services/storage/storage.service.js.html +172 -0
  122. package/coverage/core/api/services/tags/index.html +116 -0
  123. package/coverage/core/api/services/tags/tags.hooks.js.html +178 -0
  124. package/coverage/core/api/services/users/index.html +116 -0
  125. package/coverage/core/api/services/users/users.hooks.js.html +307 -0
  126. package/coverage/core/api/utils.js.html +118 -0
  127. package/coverage/core/common/errors.js.html +88 -0
  128. package/coverage/core/common/index.html +176 -0
  129. package/coverage/core/common/index.js.html +115 -0
  130. package/coverage/core/common/permissions.js.html +1048 -0
  131. package/coverage/core/common/schema.js.html +190 -0
  132. package/coverage/core/common/utils.js.html +220 -0
  133. package/coverage/favicon.png +0 -0
  134. package/coverage/index.html +491 -0
  135. package/coverage/lcov-report/base.css +224 -0
  136. package/coverage/lcov-report/block-navigation.js +87 -0
  137. package/coverage/lcov-report/core/api/application.js.html +1870 -0
  138. package/coverage/lcov-report/core/api/authentication.js.html +742 -0
  139. package/coverage/lcov-report/core/api/db.js.html +778 -0
  140. package/coverage/lcov-report/core/api/hooks/hooks.authentication.js.html +313 -0
  141. package/coverage/lcov-report/core/api/hooks/hooks.authorisations.js.html +1243 -0
  142. package/coverage/lcov-report/core/api/hooks/hooks.groups.js.html +229 -0
  143. package/coverage/lcov-report/core/api/hooks/hooks.logger.js.html +163 -0
  144. package/coverage/lcov-report/core/api/hooks/hooks.model.js.html +955 -0
  145. package/coverage/lcov-report/core/api/hooks/hooks.organisations.js.html +541 -0
  146. package/coverage/lcov-report/core/api/hooks/hooks.push.js.html +253 -0
  147. package/coverage/lcov-report/core/api/hooks/hooks.query.js.html +862 -0
  148. package/coverage/lcov-report/core/api/hooks/hooks.schemas.js.html +304 -0
  149. package/coverage/lcov-report/core/api/hooks/hooks.service.js.html +319 -0
  150. package/coverage/lcov-report/core/api/hooks/hooks.storage.js.html +193 -0
  151. package/coverage/lcov-report/core/api/hooks/hooks.users.js.html +868 -0
  152. package/coverage/lcov-report/core/api/hooks/index.html +296 -0
  153. package/coverage/lcov-report/core/api/hooks/index.js.html +121 -0
  154. package/coverage/lcov-report/core/api/index.html +191 -0
  155. package/coverage/lcov-report/core/api/index.js.html +148 -0
  156. package/coverage/lcov-report/core/api/marshall.js.html +448 -0
  157. package/coverage/lcov-report/core/api/models/groups.model.mongodb.js.html +109 -0
  158. package/coverage/lcov-report/core/api/models/index.html +161 -0
  159. package/coverage/lcov-report/core/api/models/organisations.model.mongodb.js.html +94 -0
  160. package/coverage/lcov-report/core/api/models/tags.model.mongodb.js.html +115 -0
  161. package/coverage/lcov-report/core/api/models/users.model.mongodb.js.html +115 -0
  162. package/coverage/lcov-report/core/api/services/account/account.hooks.js.html +208 -0
  163. package/coverage/lcov-report/core/api/services/account/account.service.js.html +436 -0
  164. package/coverage/lcov-report/core/api/services/account/index.html +131 -0
  165. package/coverage/lcov-report/core/api/services/authorisations/authorisations.hooks.js.html +184 -0
  166. package/coverage/lcov-report/core/api/services/authorisations/authorisations.service.js.html +502 -0
  167. package/coverage/lcov-report/core/api/services/authorisations/index.html +131 -0
  168. package/coverage/lcov-report/core/api/services/databases/databases.hooks.js.html +193 -0
  169. package/coverage/lcov-report/core/api/services/databases/databases.service.js.html +100 -0
  170. package/coverage/lcov-report/core/api/services/databases/index.html +131 -0
  171. package/coverage/lcov-report/core/api/services/groups/groups.hooks.js.html +178 -0
  172. package/coverage/lcov-report/core/api/services/groups/index.html +116 -0
  173. package/coverage/lcov-report/core/api/services/import-export/import-export.hooks.js.html +184 -0
  174. package/coverage/lcov-report/core/api/services/import-export/import-export.service.js.html +118 -0
  175. package/coverage/lcov-report/core/api/services/import-export/index.html +131 -0
  176. package/coverage/lcov-report/core/api/services/index.html +116 -0
  177. package/coverage/lcov-report/core/api/services/index.js.html +499 -0
  178. package/coverage/lcov-report/core/api/services/mailer/index.html +131 -0
  179. package/coverage/lcov-report/core/api/services/mailer/mailer.hooks.js.html +190 -0
  180. package/coverage/lcov-report/core/api/services/mailer/mailer.service.js.html +118 -0
  181. package/coverage/lcov-report/core/api/services/organisations/index.html +131 -0
  182. package/coverage/lcov-report/core/api/services/organisations/organisations.hooks.js.html +178 -0
  183. package/coverage/lcov-report/core/api/services/organisations/organisations.service.js.html +343 -0
  184. package/coverage/lcov-report/core/api/services/push/index.html +131 -0
  185. package/coverage/lcov-report/core/api/services/push/push.hooks.js.html +190 -0
  186. package/coverage/lcov-report/core/api/services/push/push.service.js.html +121 -0
  187. package/coverage/lcov-report/core/api/services/storage/index.html +131 -0
  188. package/coverage/lcov-report/core/api/services/storage/storage.hooks.js.html +190 -0
  189. package/coverage/lcov-report/core/api/services/storage/storage.service.js.html +172 -0
  190. package/coverage/lcov-report/core/api/services/tags/index.html +116 -0
  191. package/coverage/lcov-report/core/api/services/tags/tags.hooks.js.html +178 -0
  192. package/coverage/lcov-report/core/api/services/users/index.html +116 -0
  193. package/coverage/lcov-report/core/api/services/users/users.hooks.js.html +307 -0
  194. package/coverage/lcov-report/core/api/utils.js.html +118 -0
  195. package/coverage/lcov-report/core/common/errors.js.html +88 -0
  196. package/coverage/lcov-report/core/common/index.html +176 -0
  197. package/coverage/lcov-report/core/common/index.js.html +115 -0
  198. package/coverage/lcov-report/core/common/permissions.js.html +1048 -0
  199. package/coverage/lcov-report/core/common/schema.js.html +190 -0
  200. package/coverage/lcov-report/core/common/utils.js.html +220 -0
  201. package/coverage/lcov-report/favicon.png +0 -0
  202. package/coverage/lcov-report/index.html +491 -0
  203. package/coverage/lcov-report/map/api/hooks/hooks.catalog.js.html +457 -0
  204. package/coverage/lcov-report/map/api/hooks/hooks.features.js.html +397 -0
  205. package/coverage/lcov-report/map/api/hooks/hooks.query.js.html +1309 -0
  206. package/coverage/lcov-report/map/api/hooks/index.html +161 -0
  207. package/coverage/lcov-report/map/api/hooks/index.js.html +94 -0
  208. package/coverage/lcov-report/map/api/index.html +131 -0
  209. package/coverage/lcov-report/map/api/index.js.html +139 -0
  210. package/coverage/lcov-report/map/api/marshall.js.html +178 -0
  211. package/coverage/lcov-report/map/api/models/alerts.model.mongodb.js.html +106 -0
  212. package/coverage/lcov-report/map/api/models/catalog.model.mongodb.js.html +127 -0
  213. package/coverage/lcov-report/map/api/models/features.model.mongodb.js.html +196 -0
  214. package/coverage/lcov-report/map/api/models/index.html +161 -0
  215. package/coverage/lcov-report/map/api/models/projects.model.mongodb.js.html +109 -0
  216. package/coverage/lcov-report/map/api/services/alerts/alerts.hooks.js.html +274 -0
  217. package/coverage/lcov-report/map/api/services/alerts/alerts.service.js.html +610 -0
  218. package/coverage/lcov-report/map/api/services/alerts/index.html +131 -0
  219. package/coverage/lcov-report/map/api/services/catalog/catalog.hooks.js.html +316 -0
  220. package/coverage/lcov-report/map/api/services/catalog/index.html +116 -0
  221. package/coverage/lcov-report/map/api/services/daptiles/daptiles.service.js.html +1510 -0
  222. package/coverage/lcov-report/map/api/services/daptiles/index.html +116 -0
  223. package/coverage/lcov-report/map/api/services/features/features.hooks.js.html +241 -0
  224. package/coverage/lcov-report/map/api/services/features/features.service.js.html +241 -0
  225. package/coverage/lcov-report/map/api/services/features/index.html +131 -0
  226. package/coverage/lcov-report/map/api/services/index.html +116 -0
  227. package/coverage/lcov-report/map/api/services/index.js.html +817 -0
  228. package/coverage/lcov-report/map/api/services/projects/index.html +116 -0
  229. package/coverage/lcov-report/map/api/services/projects/projects.hooks.js.html +439 -0
  230. package/coverage/lcov-report/map/common/dynamic-grid-source.js.html +466 -0
  231. package/coverage/lcov-report/map/common/errors.js.html +94 -0
  232. package/coverage/lcov-report/map/common/geotiff-grid-source.js.html +541 -0
  233. package/coverage/lcov-report/map/common/grid.js.html +1612 -0
  234. package/coverage/lcov-report/map/common/index.html +371 -0
  235. package/coverage/lcov-report/map/common/index.js.html +172 -0
  236. package/coverage/lcov-report/map/common/meteo-model-grid-source.js.html +556 -0
  237. package/coverage/lcov-report/map/common/moment-utils.js.html +157 -0
  238. package/coverage/lcov-report/map/common/opendap-grid-source.js.html +868 -0
  239. package/coverage/lcov-report/map/common/opendap-utils.js.html +826 -0
  240. package/coverage/lcov-report/map/common/permissions.js.html +124 -0
  241. package/coverage/lcov-report/map/common/time-based-grid-source.js.html +418 -0
  242. package/coverage/lcov-report/map/common/tms-utils.js.html +274 -0
  243. package/coverage/lcov-report/map/common/wcs-grid-source.js.html +364 -0
  244. package/coverage/lcov-report/map/common/wcs-utils.js.html +586 -0
  245. package/coverage/lcov-report/map/common/weacast-grid-source.js.html +1033 -0
  246. package/coverage/lcov-report/map/common/wfs-utils.js.html +574 -0
  247. package/coverage/lcov-report/map/common/wms-utils.js.html +451 -0
  248. package/coverage/lcov-report/map/common/wmts-utils.js.html +547 -0
  249. package/coverage/lcov-report/prettify.css +1 -0
  250. package/coverage/lcov-report/prettify.js +2 -0
  251. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  252. package/coverage/lcov-report/sorter.js +196 -0
  253. package/coverage/lcov.info +11128 -0
  254. package/coverage/map/api/hooks/hooks.catalog.js.html +457 -0
  255. package/coverage/map/api/hooks/hooks.features.js.html +397 -0
  256. package/coverage/map/api/hooks/hooks.query.js.html +1309 -0
  257. package/coverage/map/api/hooks/index.html +161 -0
  258. package/coverage/map/api/hooks/index.js.html +94 -0
  259. package/coverage/map/api/index.html +131 -0
  260. package/coverage/map/api/index.js.html +139 -0
  261. package/coverage/map/api/marshall.js.html +178 -0
  262. package/coverage/map/api/models/alerts.model.mongodb.js.html +106 -0
  263. package/coverage/map/api/models/catalog.model.mongodb.js.html +127 -0
  264. package/coverage/map/api/models/features.model.mongodb.js.html +196 -0
  265. package/coverage/map/api/models/index.html +161 -0
  266. package/coverage/map/api/models/projects.model.mongodb.js.html +109 -0
  267. package/coverage/map/api/services/alerts/alerts.hooks.js.html +274 -0
  268. package/coverage/map/api/services/alerts/alerts.service.js.html +610 -0
  269. package/coverage/map/api/services/alerts/index.html +131 -0
  270. package/coverage/map/api/services/catalog/catalog.hooks.js.html +316 -0
  271. package/coverage/map/api/services/catalog/index.html +116 -0
  272. package/coverage/map/api/services/daptiles/daptiles.service.js.html +1510 -0
  273. package/coverage/map/api/services/daptiles/index.html +116 -0
  274. package/coverage/map/api/services/features/features.hooks.js.html +241 -0
  275. package/coverage/map/api/services/features/features.service.js.html +241 -0
  276. package/coverage/map/api/services/features/index.html +131 -0
  277. package/coverage/map/api/services/index.html +116 -0
  278. package/coverage/map/api/services/index.js.html +817 -0
  279. package/coverage/map/api/services/projects/index.html +116 -0
  280. package/coverage/map/api/services/projects/projects.hooks.js.html +439 -0
  281. package/coverage/map/common/dynamic-grid-source.js.html +466 -0
  282. package/coverage/map/common/errors.js.html +94 -0
  283. package/coverage/map/common/geotiff-grid-source.js.html +541 -0
  284. package/coverage/map/common/grid.js.html +1612 -0
  285. package/coverage/map/common/index.html +371 -0
  286. package/coverage/map/common/index.js.html +172 -0
  287. package/coverage/map/common/meteo-model-grid-source.js.html +556 -0
  288. package/coverage/map/common/moment-utils.js.html +157 -0
  289. package/coverage/map/common/opendap-grid-source.js.html +868 -0
  290. package/coverage/map/common/opendap-utils.js.html +826 -0
  291. package/coverage/map/common/permissions.js.html +124 -0
  292. package/coverage/map/common/time-based-grid-source.js.html +418 -0
  293. package/coverage/map/common/tms-utils.js.html +274 -0
  294. package/coverage/map/common/wcs-grid-source.js.html +364 -0
  295. package/coverage/map/common/wcs-utils.js.html +586 -0
  296. package/coverage/map/common/weacast-grid-source.js.html +1033 -0
  297. package/coverage/map/common/wfs-utils.js.html +574 -0
  298. package/coverage/map/common/wms-utils.js.html +451 -0
  299. package/coverage/map/common/wmts-utils.js.html +547 -0
  300. package/coverage/prettify.css +1 -0
  301. package/coverage/prettify.js +2 -0
  302. package/coverage/sort-arrow-sprite.png +0 -0
  303. package/coverage/sorter.js +196 -0
  304. package/coverage/tmp/coverage-137435-1719398750767-0.json +1 -0
  305. package/coverage/tmp/coverage-137447-1719398750752-0.json +1 -0
  306. package/coverage/tmp/coverage-137458-1719398750740-0.json +1 -0
  307. package/coverage/tmp/coverage-137470-1719398750728-0.json +1 -0
  308. package/coverage/tmp/coverage-137477-1719398750691-0.json +1 -0
  309. package/map/api/hooks/hooks.query.js +5 -2
  310. package/map/api/services/catalog/catalog.hooks.js +4 -5
  311. package/map/client/cesium/utils/index.js +2 -1
  312. package/map/client/cesium/utils/utils.cesium.js +8 -0
  313. package/map/client/cesium/utils/utils.features.js +2 -2
  314. package/map/client/cesium/utils/utils.style.js +19 -17
  315. package/map/client/components/KCompass.vue +25 -3
  316. package/map/client/components/KEditLayerData.vue +1 -1
  317. package/map/client/components/KPositionIndicator.vue +1 -1
  318. package/map/client/components/catalog/KConnectLayer.vue +2 -2
  319. package/map/client/components/catalog/KCreateView.vue +2 -2
  320. package/map/client/components/form/KDirectionField.vue +4 -0
  321. package/map/client/components/form/KOwsLayerField.vue +4 -4
  322. package/map/client/components/form/KOwsServiceField.vue +3 -4
  323. package/map/client/components/legend/KLegend.vue +13 -15
  324. package/map/client/components/tools/KGeolocateTool.vue +1 -1
  325. package/map/client/components/widget/KStackableTimeSeries.vue +3 -0
  326. package/map/client/composables/highlight.js +4 -1
  327. package/map/client/elevation-utils.js +2 -2
  328. package/map/client/i18n/map_en.json +3 -1
  329. package/map/client/i18n/map_fr.json +3 -1
  330. package/map/client/mixins/globe/mixin.base-globe.js +121 -80
  331. package/map/client/mixins/globe/mixin.file-layers.js +2 -2
  332. package/map/client/mixins/globe/mixin.geojson-layers.js +24 -19
  333. package/map/client/mixins/globe/mixin.globe-activity.js +3 -3
  334. package/map/client/mixins/globe/mixin.opendap-layers.js +3 -3
  335. package/map/client/mixins/globe/mixin.style.js +5 -5
  336. package/map/client/mixins/globe/mixin.tooltip.js +5 -3
  337. package/map/client/mixins/map/mixin.base-map.js +42 -4
  338. package/map/client/mixins/map/mixin.canvas-layers.js +0 -1
  339. package/map/client/mixins/map/mixin.geojson-layers.js +10 -5
  340. package/map/client/mixins/mixin.activity.js +2 -2
  341. package/map/client/mixins/mixin.feature-selection.js +7 -5
  342. package/map/client/mixins/mixin.levels.js +1 -1
  343. package/map/client/utils/utils.catalog.js +15 -0
  344. package/map/client/utils/utils.location.js +2 -1
  345. package/map/client/utils/utils.style.js +1 -1
  346. package/map/common/geotiff-grid-source.js +5 -3
  347. package/map/common/grid.js +2 -2
  348. package/map/common/meteo-model-grid-source.js +1 -1
  349. package/map/common/time-based-grid-source.js +1 -1
  350. package/map/common/wmts-utils.js +11 -11
  351. package/package.json +12 -8
  352. package/scripts/build_docs.sh +37 -0
  353. package/scripts/init_runner.sh +30 -0
  354. package/scripts/kash/.github/workflows/run_tests.yaml +33 -0
  355. package/scripts/kash/README.md +2 -0
  356. package/scripts/kash/kash.sh +1657 -0
  357. package/scripts/kash/scripts/run_tests.sh +151 -0
  358. package/scripts/run_tests.sh +48 -0
  359. package/scripts/setup_workspace.sh +42 -0
  360. package/test/api/core/hooks.test.js +31 -0
  361. package/test/api/core/test-log-2023-12-19.log +7 -0
  362. package/test/api/core/test-log-2024-01-04.log +14 -0
  363. package/test/api/core/test-log-2024-05-14.log +6 -0
  364. package/test/api/core/test-log-2024-06-06.log +23 -0
  365. package/test/api/core/test-log-2024-06-26.log +25 -0
  366. package/test/api/map/grid-sources.test.js +3 -1
  367. package/test/api/map/hooks.test.js +58 -12
  368. package/test/api/map/test-log-2023-11-24.log +121 -0
  369. package/test/api/map/test-log-2023-12-12.log +29 -0
  370. package/test/api/map/test-log-2023-12-13.log +5 -0
  371. package/test/api/map/test-log-2024-01-04.log +2 -0
  372. package/test/api/map/test-log-2024-01-11.log +1 -0
  373. package/test/api/map/test-log-2024-01-25.log +19 -0
  374. package/test/api/map/test-log-2024-06-06.log +39 -0
  375. package/test/client/core/collection.js +2 -2
  376. package/test/client/core/dialogs.js +13 -0
  377. package/test/client/core/index.js +6 -5
  378. package/test/client/core/layout.js +1 -13
  379. package/test/client/core/runner.js +41 -20
  380. package/test/client/core/screens.js +6 -0
  381. package/test/client/core/utils.js +23 -19
  382. package/.travis.doc.sh +0 -8
  383. package/.travis.test.sh +0 -72
  384. package/core/client/components/KAction.vue +0 -393
  385. package/core/client/components/KBlock.vue +0 -67
  386. package/core/client/components/app/KTerms.vue +0 -41
@@ -142,6 +142,7 @@ export function asGeoJson (options = {}) {
142
142
  const latitudeProperty = (options.latitudeProperty || 'latitude')
143
143
  const altitudeProperty = (options.altitudeProperty || 'altitude')
144
144
  const geometryProperty = (options.geometryProperty || 'geometry')
145
+ const allowNullGeometries = _.get(options, 'allowNullGeometries', false)
145
146
  let results = _.get(hook, options.dataPath || 'result')
146
147
  // Already as GeoJson ?
147
148
  if (results.type === 'FeatureCollection') return
@@ -159,7 +160,9 @@ export function asGeoJson (options = {}) {
159
160
  Array.isArray(_.get(item, geometryProperty)) ||
160
161
  // Check for a geometry property (previously provided or already transformed item)
161
162
  (_.has(item, geometryProperty + '.type') && _.has(item, geometryProperty + '.coordinates')) ||
162
- (_.has(item, geometryProperty + '.geometry.type') && _.has(item, geometryProperty + '.geometry.coordinates'))
163
+ (_.has(item, geometryProperty + '.geometry.type') && _.has(item, geometryProperty + '.geometry.coordinates')) ||
164
+ // Check for null geometries when allowed
165
+ allowNullGeometries
163
166
  })
164
167
  .map(item => {
165
168
  let coordinates
@@ -194,7 +197,7 @@ export function asGeoJson (options = {}) {
194
197
  // Item locations are not already in GeoJson feature format so we need to convert
195
198
  return Object.assign({
196
199
  type: 'Feature',
197
- geometry: { type: 'Point', coordinates },
200
+ geometry: (coordinates ? { type: 'Point', coordinates } : null),
198
201
  properties: {}
199
202
  }, _.omit(item, [longitudeProperty, latitudeProperty]))
200
203
  }
@@ -4,11 +4,11 @@ import fuzzySearch from 'feathers-mongodb-fuzzy-search'
4
4
  import { hooks as coreHooks } from '../../../../core/api/index.js'
5
5
  import { filterLayers, updateLayerReferences, updateProjects, getDefaultCategories, getDefaultSublegends } from '../../hooks/index.js'
6
6
 
7
- const { setNow, discard } = common
7
+ const { setNow, discard, when } = common
8
8
 
9
9
  export default {
10
10
  before: {
11
- all: [],
11
+ all: [coreHooks.marshallHttpQuery],
12
12
  find: [
13
13
  fuzzySearch({ fields: ['name'] }), coreHooks.diacriticSearch(), filterLayers, coreHooks.distinct
14
14
  ],
@@ -47,9 +47,8 @@ export default {
47
47
  coreHooks.convertToJson(['schema.content', 'filters'])
48
48
  ],
49
49
  find: [
50
- // Merge built-in categories with user-defined ones
51
- getDefaultCategories,
52
- getDefaultSublegends
50
+ // Merge built-in categoriessublegends with user-defined ones for global catalog only
51
+ when(hook => !hook.service.getContextId(), getDefaultCategories, getDefaultSublegends)
53
52
  ],
54
53
  get: [],
55
54
  create: [],
@@ -1,4 +1,5 @@
1
+ export * from './utils.cesium.js'
1
2
  export * from './utils.events.js'
2
3
  export * from './utils.popup.js'
3
4
  export * from './utils.style.js'
4
- export * from './utils.features.js'
5
+ export * from './utils.features.js'
@@ -0,0 +1,8 @@
1
+ // We need to dynamically import cesium to dynamically get constructors
2
+ export let Cesium
3
+
4
+ async function loadCesium() {
5
+ Cesium = await import(`cesium`)
6
+ }
7
+
8
+ loadCesium()
@@ -1,8 +1,8 @@
1
1
  import { kml } from '@tmcw/togeojson'
2
- import Cesium from 'cesium/Source/Cesium.js'
2
+ import { exportKml } from 'cesium'
3
3
 
4
4
  export async function convertEntitiesToGeoJson(entities) {
5
- const kmlEntities = await Cesium.exportKml({ entities, modelCallback: () => '' })
5
+ const kmlEntities = await exportKml({ entities, modelCallback: () => '' })
6
6
  const parser = new DOMParser()
7
7
  return kml(parser.parseFromString(kmlEntities.kml, 'application/xml'))
8
8
  }
@@ -1,11 +1,12 @@
1
1
  import _ from 'lodash'
2
2
  import chroma from 'chroma-js'
3
3
  import moment from 'moment'
4
- import Cesium from 'cesium/Source/Cesium.js'
4
+ import { Color } from 'cesium'
5
5
  import { Time, Units } from '../../../../core/client/index.js'
6
6
  import { convertPointStyleToSimpleStyle, convertLineStyleToSimpleStyle, convertPolygonStyleToSimpleStyle, convertSimpleStyleColors,
7
7
  convertSimpleStyleToPointStyle, convertSimpleStyleToLineStyle, convertSimpleStyleToPolygonStyle,
8
8
  PointStyleTemplateMappings, LineStyleTemplateMappings, PolygonStyleTemplateMappings } from '../../utils/utils.style.js'
9
+ import { Cesium } from './utils.cesium.js'
9
10
 
10
11
  export const CesiumStyleMappings = {
11
12
  stroke: 'stroke',
@@ -34,7 +35,7 @@ export function convertToCesiumFromSimpleStyle (style, inPlace) {
34
35
  if (inPlace) _.unset(style, key)
35
36
  // Convert from string to color object as required by cesium
36
37
  if ((typeof value === 'string') && ['markerColor', 'fill', 'stroke'].includes(mapping)) {
37
- _.set(convertedStyle, mapping, Cesium.Color.fromCssColorString(value))
38
+ _.set(convertedStyle, mapping, Color.fromCssColorString(value))
38
39
  }
39
40
  }
40
41
  })
@@ -85,21 +86,22 @@ export function getPolygonSimpleStyle (feature, options, engine, engineStylePath
85
86
  return convertSimpleStyleColors(convertPolygonStyleToSimpleStyle(style))
86
87
  }
87
88
 
89
+ // Helper to convert from string to objects
90
+ export function createCesiumObject () {
91
+ const args = Array.from(arguments)
92
+ const constructor = args[0]
93
+ args.shift()
94
+ const Class = _.get(Cesium, constructor)
95
+ // Can be callable, constructable or constant
96
+ let object
97
+ if (typeof Class === 'function') {
98
+ try { object = Class(...args) } catch (error) { /* Simply avoid raising any error */ }
99
+ try { object = new Class(...args) } catch (error) { /* Simply avoid raising any error */ }
100
+ } else object = Class
101
+ return object
102
+ }
103
+
88
104
  export function convertToCesiumObjects (style) {
89
- // Helper to convert from string to objects
90
- function createCesiumObject () {
91
- const args = Array.from(arguments)
92
- const constructor = args[0]
93
- args.shift()
94
- const Class = _.get(Cesium, constructor)
95
- // Can be callable, constructable or constant
96
- let object
97
- if (typeof Class === 'function') {
98
- try { object = Class(...args) } catch (error) { /* Simply avoid raising any error */ }
99
- try { object = new Class(...args) } catch (error) { /* Simply avoid raising any error */ }
100
- } else object = Class
101
- return object
102
- }
103
105
  const mapValue = (value) => {
104
106
  if (typeof value === 'object') {
105
107
  const type = value.type
@@ -134,4 +136,4 @@ export function convertToCesiumObjects (style) {
134
136
  } else {
135
137
  return _.mapValues({ value: style }, mapValue).value
136
138
  }
137
- }
139
+ }
@@ -5,7 +5,7 @@
5
5
  @touchstart="onStartDrag"
6
6
  style="position: relative"
7
7
  >
8
- <svg width="100%" heigh="100%" viewBox="0 0 100 100" onclick="computeDirection">
8
+ <svg width="100%" heigh="100%" viewBox="0 0 100 100">
9
9
  <circle
10
10
  cx="50" cy="50" r="44"
11
11
  :stroke="getCssVar('accent')"
@@ -42,7 +42,7 @@
42
42
  color="primary"
43
43
  text-color="white"
44
44
  outline
45
- :label="`${modelValue}°`"
45
+ :label="getLabel()"
46
46
  />
47
47
  <q-popup-edit
48
48
  v-model="direction"
@@ -51,6 +51,7 @@
51
51
  >
52
52
  <q-input
53
53
  v-model.number="scope.value"
54
+ :prefix="getPrefix()"
54
55
  suffix="°"
55
56
  autofocus
56
57
  dense
@@ -64,6 +65,7 @@
64
65
  <script setup>
65
66
  import { ref, computed } from 'vue'
66
67
  import { getCssVar } from 'quasar'
68
+ import { i18n } from '../../../core/client'
67
69
 
68
70
  // Props
69
71
  const props = defineProps({
@@ -78,6 +80,13 @@ const props = defineProps({
78
80
  ticks: {
79
81
  type: Number,
80
82
  default: 16
83
+ },
84
+ labelMode: {
85
+ type: String,
86
+ default: 'from',
87
+ validator (value) {
88
+ return ['from', 'from-to'].includes(value)
89
+ }
81
90
  }
82
91
  })
83
92
 
@@ -122,12 +131,25 @@ function onHandleDrag (event) {
122
131
  const { x, y } = event.type.startsWith('touch') ? event.changedTouches[0] : event
123
132
  computeDirection(x, y)
124
133
  }
134
+ function getLabel () {
135
+ if (props.labelMode === 'from') return `${direction.value}°`
136
+ return i18n.t('KCompass.FROM_TO', {
137
+ direction: direction.value,
138
+ source: (direction.value + 180) % 360
139
+ })
140
+ }
141
+ function getPrefix () {
142
+ if (props.labelMode === 'from') return ''
143
+ return i18n.t('KCompass.FROM')
144
+ }
125
145
  function onStartDrag (event) {
146
+ const { x, y } = event
147
+ computeDirection(x, y)
126
148
  window.addEventListener('mousemove', onHandleDrag)
127
149
  window.addEventListener('touchmove', onHandleDrag)
128
150
  window.addEventListener('mouseup', onStropDrag)
129
151
  window.addEventListener('touchend', onStropDrag)
130
- };
152
+ }
131
153
  function onStropDrag () {
132
154
  window.removeEventListener('mousemove', onHandleDrag)
133
155
  window.removeEventListener('touchmove', onHandleDrag)
@@ -3,7 +3,7 @@
3
3
  </template>
4
4
 
5
5
  <script>
6
- import KAction from '../../../core/client/components/KAction.vue'
6
+ import KAction from '../../../core/client/components/action/KAction.vue'
7
7
 
8
8
  export default {
9
9
  name: 'k-edit-layer-data',
@@ -19,7 +19,7 @@ import _ from 'lodash'
19
19
  import { copyToClipboard } from 'quasar'
20
20
  import { Layout, utils as kdkCoreUtils } from '../../../core.client'
21
21
  import { formatUserCoordinates } from '../utils'
22
- import KAction from '../../../core/client/components/KAction.vue'
22
+ import KAction from '../../../core/client/components/action/KAction.vue'
23
23
 
24
24
  export default {
25
25
  components: {
@@ -284,7 +284,7 @@ export default {
284
284
 
285
285
  const url = wmts.buildLeafletUrl(this.service.baseUrl, this.layer, {
286
286
  version: this.service.version,
287
- style: style,
287
+ style,
288
288
  crs: '3857',
289
289
  format: pickedFormat,
290
290
  searchParams: this.service.searchParams,
@@ -295,7 +295,7 @@ export default {
295
295
  url: url.replace('{z}', '{TileMatrix}').replace('{x}', '{TileCol}').replace('{y}', '{TileRow}'),
296
296
  format: pickedFormat,
297
297
  layer: this.layer.id,
298
- style: style,
298
+ style,
299
299
  tileMatrixSetID: this.layer.crs['3857']
300
300
  }
301
301
  newLayer.leaflet = {
@@ -102,8 +102,8 @@ export default {
102
102
  try {
103
103
  this.creating = true
104
104
  const createdView = await this.kActivity.saveContext(view)
105
- // Add view to current project ?
106
- if (this.project) {
105
+ // Add view to current project ? Check if not coming from another planet first
106
+ if (this.project && (this.project.getPlanetApi() === this.$api)) {
107
107
  this.project.views.push({ _id: createdView._id })
108
108
  await this.$api.getService('projects').patch(this.project._id, {
109
109
  views: this.project.views
@@ -73,6 +73,7 @@
73
73
  <KCompass
74
74
  v-model="model"
75
75
  @update:model-value="onChanged"
76
+ :labelMode="labelMode"
76
77
  class="k-compass"
77
78
  />
78
79
  </template>
@@ -108,6 +109,9 @@ export default {
108
109
  mode () {
109
110
  return _.get(this.properties.field, 'mode', 'input')
110
111
  },
112
+ labelMode () {
113
+ return _.get(this.properties.field, 'labelMode', 'from')
114
+ },
111
115
  clearable () {
112
116
  return _.get(this.properties.field, 'clearable', false)
113
117
  }
@@ -71,10 +71,10 @@ export default {
71
71
  // sort alphabetically layers per display
72
72
  return this.service
73
73
  ? _.map(this.service.availableLayers, (value, key) => value).sort((a, b) => {
74
- const uppera = a.display.toUpperCase()
75
- const upperb = b.display.toUpperCase()
76
- return uppera < upperb ? -1 : uppera > upperb ? 1 : 0
77
- })
74
+ const uppera = a.display.toUpperCase()
75
+ const upperb = b.display.toUpperCase()
76
+ return uppera < upperb ? -1 : uppera > upperb ? 1 : 0
77
+ })
78
78
  : []
79
79
  }
80
80
  },
@@ -161,10 +161,9 @@ export default {
161
161
  // fetch content and try to convert to json
162
162
  const query = url.href
163
163
 
164
- caps = await fetch(query, { redirect: 'follow' })
165
- .then(resp => resp.text())
166
- .then(txt => xml2js.parseStringPromise(txt, { tagNameProcessors: [xml2js.processors.stripPrefix] }))
167
-
164
+ const resp = await fetch(query, { redirect: 'follow' })
165
+ const txt = await resp.text()
166
+ caps = await xml2js.parseStringPromise(txt, { tagNameProcessors: [xml2js.processors.stripPrefix] })
168
167
  // look for SERVICE=xxx
169
168
  const protocol = this.findQueryParameter(url.searchParams, 'SERVICE')
170
169
  if (protocol === 'WMS') result.protocol = 'WMS'
@@ -49,9 +49,9 @@
49
49
  <script setup>
50
50
  import _ from 'lodash'
51
51
  import logger from 'loglevel'
52
- import sift from 'sift'
53
52
  import { ref, computed, watch } from 'vue'
54
- import { i18n, Store } from '../../../../core/client'
53
+ import { api, i18n, Store } from '../../../../core/client'
54
+ import { getLayersBySublegend } from '../../utils'
55
55
  import { useCurrentActivity, useCatalog } from '../../composables'
56
56
  import KLayerLegend from './KLayerLegend.vue'
57
57
 
@@ -86,6 +86,13 @@ const props = defineProps({
86
86
  }
87
87
  })
88
88
 
89
+ // Get current project for activity if any
90
+ const { getActivityProject } = useCurrentActivity({ selection: false, probe: false })
91
+ const project = getActivityProject()
92
+ // We expect the project object to expose the underlying API
93
+ const planetApi = project && typeof project.getPlanetApi === 'function' ? project.getPlanetApi() : api
94
+ // Use target catalog according to project
95
+ const { getSublegends: getProjectSublegends } = useCatalog({ project, planetApi })
89
96
  // Use global catalog
90
97
  const { getSublegends } = useCatalog()
91
98
  // Use local catalog if any
@@ -99,19 +106,7 @@ const engine = ref()
99
106
  const zoom = ref()
100
107
 
101
108
  // Computed
102
- const layersBySublegend = computed(() => {
103
- const result = {}
104
- _.forEach(sublegends.value, sublegend => {
105
- // Built-in legends use filtering while
106
- let filter = null
107
- if (_.has(sublegend, 'options.filter')) {
108
- filter = _.get(sublegend, 'options.filter')
109
- }
110
- // If the list of layers in category is empty we can have a null filter
111
- result[sublegend.name] = filter ? _.filter(layers.value, sift(filter)) : []
112
- })
113
- return result
114
- })
109
+ const layersBySublegend = computed(() => getLayersBySublegend(layers.value, sublegends.value))
115
110
 
116
111
  // Functions
117
112
  function onShowLayer (layer, engine) {
@@ -152,6 +147,9 @@ watch([() => props.sublegends, () => props.sublegendsFromCatalog], async () => {
152
147
  // Retrieve the legends from catalog if required
153
148
  if (props.sublegendsFromCatalog) {
154
149
  sublegends.value = await getSublegends()
150
+ if (project) {
151
+ sublegends.value = sublegends.value.concat(await getProjectSublegends())
152
+ }
155
153
  if (Store.get('context')) {
156
154
  sublegends.value = sublegends.value.concat(await getContextSublegends())
157
155
  }
@@ -12,7 +12,7 @@
12
12
 
13
13
  <script setup>
14
14
  import { ref, onMounted, onBeforeUnmount } from 'vue'
15
- import KAction from '../../../../core/client/components/KAction.vue'
15
+ import KAction from '../../../../core/client/components/action/KAction.vue'
16
16
  import { useCurrentActivity } from '../../composables'
17
17
  import { Geolocation } from '../../geolocation.js'
18
18
 
@@ -29,6 +29,7 @@
29
29
  class="col q-pl-sm q-pr-sm"
30
30
  :schema="schema"
31
31
  :tables="getTables(timeSerie)"
32
+ :formatters="tableFormatters"
32
33
  />
33
34
  </div>
34
35
  </template>
@@ -61,6 +62,7 @@
61
62
  class="col q-pl-sm q-pr-sm"
62
63
  :schema="schema"
63
64
  :tables="getTables(timeSerie)"
65
+ :formatters="tableFormatters"
64
66
  />
65
67
  </div>
66
68
  </template>
@@ -96,6 +98,7 @@ const props = defineProps({
96
98
  schema: { type: [String, Object], default: null },
97
99
  actions: { type: Array, default: () => [] },
98
100
  chartOptions: { type: Object, default: () => ({}) },
101
+ tableFormatters: { type: Object, defaul: () => null },
99
102
  exportOptions: { type: Object, default: () => ({}) }
100
103
  })
101
104
 
@@ -8,6 +8,8 @@ import { getFeatureId, getFeatureStyleType } from '../utils.js'
8
8
  import * as composables from '../../../core/client/composables/index.js'
9
9
 
10
10
  export const HighlightsLayerName = uid()
11
+ // This ensure it is on tp of everything else
12
+ export const HighlightsZIndex = 999
11
13
 
12
14
  export function useHighlight (name, options = {}) {
13
15
  // Set default options
@@ -153,7 +155,8 @@ export function useHighlight (name, options = {}) {
153
155
  interactive: false,
154
156
  cluster: false,
155
157
  removeMissing: true,
156
- popup: { pick: [] }
158
+ popup: { pick: [] },
159
+ zIndex: HighlightsZIndex
157
160
  },
158
161
  cesium: {
159
162
  type: 'geoJson',
@@ -56,7 +56,7 @@ function fetchProfileDataset (feature, distanceUnit, altitudeUnit) {
56
56
  }
57
57
  }
58
58
 
59
- return { dataset: allCoordsHaveAltitude ? dataset : [], segments: segments }
59
+ return { dataset: allCoordsHaveAltitude ? dataset : [], segments }
60
60
  }
61
61
 
62
62
  function asArray (val) { return (Array.isArray(val) || val === undefined) ? val : [val] }
@@ -236,7 +236,7 @@ function extractElevation (queries, { noDataset, noGeojson, queryParametersInDat
236
236
  dataset.push(datasetPoint)
237
237
  }
238
238
  if (!noGeojson) {
239
- const props = { z: e, t: t }
239
+ const props = { z: e, t }
240
240
  if (queryParametersInDataset) {
241
241
  props.resolution = r
242
242
  if (w !== undefined) props.corridorWidth = w
@@ -204,7 +204,7 @@
204
204
  "TITLE": "My position",
205
205
  "METERS": "meters",
206
206
  "FEET": "feet",
207
- "POPUP": "You are within {distance} {unit} from this point",
207
+ "POPUP": "You are within {'{distance}'} {'{unit}'} from this point",
208
208
  "OUTSIDE_MAP_BOUNDS": "You seem located outside the boundaries of the map"
209
209
  },
210
210
  "schemas": {
@@ -685,6 +685,8 @@
685
685
  "LABEL": "Legend"
686
686
  },
687
687
  "KCompass": {
688
+ "FROM_TO": "From {direction}° to {source}°",
689
+ "FROM": "From",
688
690
  "NORTH": "N",
689
691
  "EAST": "E",
690
692
  "SOUTH": "S",
@@ -204,7 +204,7 @@
204
204
  "TITLE": "Ma position",
205
205
  "METERS": "mètres",
206
206
  "FEET": "pieds",
207
- "POPUP": "Vous êtes à moins de {distance} {unit} de ce point",
207
+ "POPUP": "Vous êtes à moins de {'{distance}'} {'{unit}'} de ce point",
208
208
  "OUTSIDE_MAP_BOUNDS": "Vous semblez localisé en dehors de la carte"
209
209
  },
210
210
  "schemas": {
@@ -691,6 +691,8 @@
691
691
  "LABEL": "Légende"
692
692
  },
693
693
  "KCompass": {
694
+ "FROM_TO": "De {direction}° vers {source}°",
695
+ "FROM": "De",
694
696
  "NORTH": "N",
695
697
  "EAST": "E",
696
698
  "SOUTH": "S",