@kalisio/kdk 2.5.3 → 2.6.1

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 (541) hide show
  1. package/.github/workflows/main.yaml +35 -6
  2. package/.vscode/settings.json +5 -0
  3. package/client.globe.js +8 -0
  4. package/client.js +8 -0
  5. package/client.map.js +8 -0
  6. package/core/api/hooks/hooks.push.js +3 -2
  7. package/core/api/hooks/hooks.tags.js +56 -0
  8. package/core/api/models/tags.model.mongodb.js +8 -0
  9. package/core/api/services/index.js +33 -2
  10. package/core/api/services/tags/tags.hooks.js +47 -0
  11. package/core/client/api.js +5 -5
  12. package/core/client/components/KActivity.vue +3 -2
  13. package/core/client/components/KChip.vue +2 -2
  14. package/core/client/components/KEditor.vue +3 -1
  15. package/core/client/components/KFollower.vue +4 -4
  16. package/core/client/components/KStore.vue +1 -1
  17. package/core/client/components/KTab.vue +20 -7
  18. package/core/client/components/account/KProfile.vue +9 -25
  19. package/core/client/components/action/KAction.vue +10 -10
  20. package/core/client/components/action/KToggleFullscreenAction.vue +2 -11
  21. package/core/client/components/app/KHome.vue +3 -2
  22. package/core/client/components/collection/KFilter.vue +5 -4
  23. package/core/client/components/collection/KGrid.vue +5 -1
  24. package/core/client/components/collection/KItemsFilter.vue +47 -0
  25. package/core/client/components/collection/KItemsSorter.vue +42 -0
  26. package/core/client/components/collection/KScrollDown.vue +2 -2
  27. package/core/client/components/collection/KSearchFilterControl.vue +3 -2
  28. package/core/client/components/collection/KSorter.vue +33 -37
  29. package/core/client/components/collection/KTagsFilterControl.vue +14 -40
  30. package/core/client/components/collection/KTagsFilterView.vue +10 -45
  31. package/core/client/components/collection/KTimeFilterControl.vue +6 -7
  32. package/core/client/components/collection/KTimeFilterView.vue +13 -22
  33. package/core/client/components/collection/KTimeLine.vue +18 -9
  34. package/core/client/components/form/KColorField.vue +13 -6
  35. package/core/client/components/form/KColorScaleField.vue +7 -12
  36. package/core/client/components/form/KFileField.vue +118 -89
  37. package/core/client/components/form/KForm.vue +30 -18
  38. package/core/client/components/form/KIconField.vue +4 -1
  39. package/core/client/components/form/KNumberField.vue +9 -2
  40. package/core/client/components/form/KSelectField.vue +1 -4
  41. package/core/client/components/form/KTagField.vue +229 -0
  42. package/core/client/components/form/KTextField.vue +4 -0
  43. package/core/client/components/form/KTextareaField.vue +3 -1
  44. package/core/client/components/input/KShapePicker.vue +3 -3
  45. package/core/client/components/layout/KFab.vue +32 -20
  46. package/core/client/components/layout/KPage.vue +11 -6
  47. package/core/client/components/layout/KWindow.vue +6 -1
  48. package/core/client/components/media/index.js +2 -6
  49. package/core/client/components/menu/KMenu.vue +12 -10
  50. package/core/client/components/menu/KSubMenu.vue +12 -12
  51. package/core/client/components/messages/KMessageCard.vue +13 -12
  52. package/core/client/components/messages/KMessageComposer.vue +13 -9
  53. package/core/client/components/messages/KMessagesTimeLine.vue +16 -8
  54. package/core/client/components/tags/KTagFilter.vue +99 -0
  55. package/core/client/components/tags/KTagItem.vue +65 -0
  56. package/core/client/components/tags/KTagManager.vue +198 -0
  57. package/core/client/components/tags/KTagSelection.vue +82 -0
  58. package/core/client/components/time/KDate.vue +3 -17
  59. package/core/client/components/time/KDateTime.vue +1 -1
  60. package/core/client/components/time/KTime.vue +0 -4
  61. package/core/client/composables/collection-filter.js +41 -2
  62. package/core/client/composables/collection.js +3 -3
  63. package/core/client/composables/index.js +1 -0
  64. package/core/client/composables/pwa.js +13 -0
  65. package/core/client/composables/session.js +7 -8
  66. package/core/client/composables/user.js +36 -0
  67. package/core/client/directives/index.js +1 -0
  68. package/core/client/directives/v-drop-file.js +174 -0
  69. package/core/client/document.js +2 -1
  70. package/core/client/exporter.js +17 -3
  71. package/core/client/i18n/core_en.json +34 -7
  72. package/core/client/i18n/core_fr.json +36 -9
  73. package/core/client/i18n.js +26 -11
  74. package/core/client/layout.js +5 -5
  75. package/core/client/mixins/mixin.base-activity.js +8 -5
  76. package/core/client/mixins/mixin.base-editor.js +2 -1
  77. package/core/client/mixins/mixin.base-field.js +3 -2
  78. package/core/client/mixins/mixin.base-item.js +12 -10
  79. package/core/client/mixins/mixin.service.js +3 -1
  80. package/core/client/platform.js +0 -3
  81. package/core/client/readers/reader.json.js +2 -2
  82. package/core/client/utils/index.js +2 -0
  83. package/core/client/utils/utils.collection.js +6 -6
  84. package/core/client/utils/utils.colors.js +473 -173
  85. package/core/client/utils/utils.files.js +19 -0
  86. package/core/client/utils/utils.locale.js +13 -17
  87. package/core/client/utils/utils.services.js +27 -0
  88. package/core/client/utils/utils.shapes.js +2 -2
  89. package/core/client/utils/utils.tags.js +17 -0
  90. package/core/client/utils/utils.tours.js +31 -0
  91. package/core/common/permissions.js +3 -0
  92. package/core/common/schemas/tags.update.json +35 -0
  93. package/core/common/schemas/users.update-profile.json +1 -1
  94. package/core/common/utils.js +5 -5
  95. package/coverage/core/api/application.js.html +464 -464
  96. package/coverage/core/api/authentication.js.html +219 -351
  97. package/coverage/core/api/db.js.html +194 -209
  98. package/coverage/core/api/hooks/hooks.authentication.js.html +208 -34
  99. package/coverage/core/api/hooks/hooks.authorisations.js.html +717 -432
  100. package/coverage/core/api/hooks/hooks.groups.js.html +52 -52
  101. package/coverage/core/api/hooks/hooks.logger.js.html +43 -43
  102. package/coverage/core/api/hooks/hooks.model.js.html +300 -312
  103. package/coverage/core/api/hooks/hooks.organisations.js.html +264 -264
  104. package/coverage/core/api/hooks/hooks.push.js.html +107 -119
  105. package/coverage/core/api/hooks/hooks.query.js.html +279 -279
  106. package/coverage/core/api/hooks/hooks.schemas.js.html +135 -135
  107. package/coverage/core/api/hooks/hooks.service.js.html +28 -28
  108. package/coverage/core/api/hooks/hooks.storage.js.html +7 -7
  109. package/coverage/core/api/hooks/hooks.users.js.html +478 -205
  110. package/coverage/core/api/hooks/index.html +132 -102
  111. package/coverage/core/api/hooks/index.js.html +19 -13
  112. package/coverage/core/api/index.html +69 -54
  113. package/coverage/core/api/index.js.html +25 -25
  114. package/coverage/core/api/marshall.js.html +127 -127
  115. package/coverage/core/api/models/groups.model.mongodb.js.html +26 -26
  116. package/coverage/core/api/models/index.html +66 -21
  117. package/coverage/core/api/models/messages.model.mongodb.js.html +27 -39
  118. package/coverage/core/api/models/organisations.model.mongodb.js.html +16 -16
  119. package/coverage/core/api/models/tags.model.mongodb.js.html +30 -30
  120. package/coverage/core/api/models/users.model.mongodb.js.html +11 -11
  121. package/coverage/core/api/services/account/account.hooks.js.html +46 -46
  122. package/coverage/core/api/services/account/account.service.js.html +139 -139
  123. package/coverage/core/api/services/account/index.html +22 -22
  124. package/coverage/core/api/services/authorisations/authorisations.hooks.js.html +34 -34
  125. package/coverage/core/api/services/authorisations/authorisations.service.js.html +230 -221
  126. package/coverage/core/api/services/authorisations/index.html +20 -20
  127. package/coverage/core/api/services/databases/databases.hooks.js.html +1 -1
  128. package/coverage/core/api/services/databases/databases.service.js.html +1 -1
  129. package/coverage/core/api/services/databases/index.html +1 -1
  130. package/coverage/core/api/services/groups/groups.hooks.js.html +72 -72
  131. package/coverage/core/api/services/groups/index.html +21 -21
  132. package/coverage/core/api/services/import-export/import-export.hooks.js.html +76 -76
  133. package/coverage/core/api/services/import-export/import-export.service.js.html +32 -32
  134. package/coverage/core/api/services/import-export/index.html +32 -32
  135. package/coverage/core/api/services/index.html +21 -21
  136. package/coverage/core/api/services/index.js.html +195 -171
  137. package/coverage/core/api/services/mailer/index.html +32 -32
  138. package/coverage/core/api/services/mailer/mailer.hooks.js.html +80 -80
  139. package/coverage/core/api/services/mailer/mailer.service.js.html +32 -32
  140. package/coverage/core/api/services/messages/index.html +21 -21
  141. package/coverage/core/api/services/messages/messages.hooks.js.html +76 -94
  142. package/coverage/core/api/services/organisations/index.html +32 -32
  143. package/coverage/core/api/services/organisations/organisations.hooks.js.html +72 -72
  144. package/coverage/core/api/services/organisations/organisations.service.js.html +163 -163
  145. package/coverage/core/api/services/push/index.html +32 -32
  146. package/coverage/core/api/services/push/push.hooks.js.html +80 -80
  147. package/coverage/core/api/services/push/push.service.js.html +34 -34
  148. package/coverage/core/api/services/storage/index.html +29 -29
  149. package/coverage/core/api/services/storage/storage.hooks.js.html +80 -80
  150. package/coverage/core/api/services/storage/storage.service.js.html +37 -37
  151. package/coverage/core/api/services/tags/index.html +21 -21
  152. package/coverage/core/api/services/tags/tags.hooks.js.html +72 -72
  153. package/coverage/core/api/services/users/index.html +12 -27
  154. package/coverage/core/api/services/users/users.hooks.js.html +84 -87
  155. package/coverage/core/api/utils.js.html +1 -1
  156. package/coverage/core/common/errors.js.html +2 -2
  157. package/coverage/core/common/index.html +32 -47
  158. package/coverage/core/common/index.js.html +11 -11
  159. package/coverage/core/common/permissions.js.html +579 -264
  160. package/coverage/core/common/schema.js.html +26 -26
  161. package/coverage/core/common/utils.js.html +59 -65
  162. package/coverage/index.html +286 -256
  163. package/coverage/lcov-report/core/api/application.js.html +464 -464
  164. package/coverage/lcov-report/core/api/authentication.js.html +219 -351
  165. package/coverage/lcov-report/core/api/db.js.html +194 -209
  166. package/coverage/lcov-report/core/api/hooks/hooks.authentication.js.html +208 -34
  167. package/coverage/lcov-report/core/api/hooks/hooks.authorisations.js.html +717 -432
  168. package/coverage/lcov-report/core/api/hooks/hooks.groups.js.html +52 -52
  169. package/coverage/lcov-report/core/api/hooks/hooks.logger.js.html +43 -43
  170. package/coverage/lcov-report/core/api/hooks/hooks.model.js.html +300 -312
  171. package/coverage/lcov-report/core/api/hooks/hooks.organisations.js.html +264 -264
  172. package/coverage/lcov-report/core/api/hooks/hooks.push.js.html +107 -119
  173. package/coverage/lcov-report/core/api/hooks/hooks.query.js.html +279 -279
  174. package/coverage/lcov-report/core/api/hooks/hooks.schemas.js.html +135 -135
  175. package/coverage/lcov-report/core/api/hooks/hooks.service.js.html +28 -28
  176. package/coverage/lcov-report/core/api/hooks/hooks.storage.js.html +7 -7
  177. package/coverage/lcov-report/core/api/hooks/hooks.users.js.html +478 -205
  178. package/coverage/lcov-report/core/api/hooks/index.html +132 -102
  179. package/coverage/lcov-report/core/api/hooks/index.js.html +19 -13
  180. package/coverage/lcov-report/core/api/index.html +69 -54
  181. package/coverage/lcov-report/core/api/index.js.html +25 -25
  182. package/coverage/lcov-report/core/api/marshall.js.html +127 -127
  183. package/coverage/lcov-report/core/api/models/groups.model.mongodb.js.html +26 -26
  184. package/coverage/lcov-report/core/api/models/index.html +66 -21
  185. package/coverage/lcov-report/core/api/models/messages.model.mongodb.js.html +27 -39
  186. package/coverage/lcov-report/core/api/models/organisations.model.mongodb.js.html +16 -16
  187. package/coverage/lcov-report/core/api/models/tags.model.mongodb.js.html +30 -30
  188. package/coverage/lcov-report/core/api/models/users.model.mongodb.js.html +11 -11
  189. package/coverage/lcov-report/core/api/services/account/account.hooks.js.html +46 -46
  190. package/coverage/lcov-report/core/api/services/account/account.service.js.html +139 -139
  191. package/coverage/lcov-report/core/api/services/account/index.html +22 -22
  192. package/coverage/lcov-report/core/api/services/authorisations/authorisations.hooks.js.html +34 -34
  193. package/coverage/lcov-report/core/api/services/authorisations/authorisations.service.js.html +230 -221
  194. package/coverage/lcov-report/core/api/services/authorisations/index.html +20 -20
  195. package/coverage/lcov-report/core/api/services/databases/databases.hooks.js.html +1 -1
  196. package/coverage/lcov-report/core/api/services/databases/databases.service.js.html +1 -1
  197. package/coverage/lcov-report/core/api/services/databases/index.html +1 -1
  198. package/coverage/lcov-report/core/api/services/groups/groups.hooks.js.html +72 -72
  199. package/coverage/lcov-report/core/api/services/groups/index.html +21 -21
  200. package/coverage/lcov-report/core/api/services/import-export/import-export.hooks.js.html +76 -76
  201. package/coverage/lcov-report/core/api/services/import-export/import-export.service.js.html +32 -32
  202. package/coverage/lcov-report/core/api/services/import-export/index.html +32 -32
  203. package/coverage/lcov-report/core/api/services/index.html +21 -21
  204. package/coverage/lcov-report/core/api/services/index.js.html +195 -171
  205. package/coverage/lcov-report/core/api/services/mailer/index.html +32 -32
  206. package/coverage/lcov-report/core/api/services/mailer/mailer.hooks.js.html +80 -80
  207. package/coverage/lcov-report/core/api/services/mailer/mailer.service.js.html +32 -32
  208. package/coverage/lcov-report/core/api/services/messages/index.html +21 -21
  209. package/coverage/lcov-report/core/api/services/messages/messages.hooks.js.html +76 -94
  210. package/coverage/lcov-report/core/api/services/organisations/index.html +32 -32
  211. package/coverage/lcov-report/core/api/services/organisations/organisations.hooks.js.html +72 -72
  212. package/coverage/lcov-report/core/api/services/organisations/organisations.service.js.html +163 -163
  213. package/coverage/lcov-report/core/api/services/push/index.html +32 -32
  214. package/coverage/lcov-report/core/api/services/push/push.hooks.js.html +80 -80
  215. package/coverage/lcov-report/core/api/services/push/push.service.js.html +34 -34
  216. package/coverage/lcov-report/core/api/services/storage/index.html +29 -29
  217. package/coverage/lcov-report/core/api/services/storage/storage.hooks.js.html +80 -80
  218. package/coverage/lcov-report/core/api/services/storage/storage.service.js.html +37 -37
  219. package/coverage/lcov-report/core/api/services/tags/index.html +21 -21
  220. package/coverage/lcov-report/core/api/services/tags/tags.hooks.js.html +72 -72
  221. package/coverage/lcov-report/core/api/services/users/index.html +12 -27
  222. package/coverage/lcov-report/core/api/services/users/users.hooks.js.html +84 -87
  223. package/coverage/lcov-report/core/api/utils.js.html +1 -1
  224. package/coverage/lcov-report/core/common/errors.js.html +2 -2
  225. package/coverage/lcov-report/core/common/index.html +32 -47
  226. package/coverage/lcov-report/core/common/index.js.html +11 -11
  227. package/coverage/lcov-report/core/common/permissions.js.html +579 -264
  228. package/coverage/lcov-report/core/common/schema.js.html +26 -26
  229. package/coverage/lcov-report/core/common/utils.js.html +59 -65
  230. package/coverage/lcov-report/index.html +286 -256
  231. package/coverage/lcov-report/map/api/hooks/hooks.catalog.js.html +257 -353
  232. package/coverage/lcov-report/map/api/hooks/hooks.features.js.html +218 -218
  233. package/coverage/lcov-report/map/api/hooks/hooks.query.js.html +810 -795
  234. package/coverage/lcov-report/map/api/hooks/index.html +54 -54
  235. package/coverage/lcov-report/map/api/hooks/index.js.html +16 -16
  236. package/coverage/lcov-report/map/api/index.html +32 -32
  237. package/coverage/lcov-report/map/api/index.js.html +46 -46
  238. package/coverage/lcov-report/map/api/marshall.js.html +72 -72
  239. package/coverage/lcov-report/map/api/models/alerts.model.mongodb.js.html +24 -24
  240. package/coverage/lcov-report/map/api/models/catalog.model.mongodb.js.html +27 -69
  241. package/coverage/lcov-report/map/api/models/features.model.mongodb.js.html +80 -80
  242. package/coverage/lcov-report/map/api/models/index.html +54 -69
  243. package/coverage/lcov-report/map/api/models/projects.model.mongodb.js.html +26 -26
  244. package/coverage/lcov-report/map/api/services/alerts/alerts.hooks.js.html +136 -136
  245. package/coverage/lcov-report/map/api/services/alerts/alerts.service.js.html +343 -343
  246. package/coverage/lcov-report/map/api/services/alerts/index.html +32 -32
  247. package/coverage/lcov-report/map/api/services/catalog/catalog.hooks.js.html +160 -178
  248. package/coverage/lcov-report/map/api/services/catalog/index.html +21 -21
  249. package/coverage/lcov-report/map/api/services/daptiles/daptiles.service.js.html +1 -1
  250. package/coverage/lcov-report/map/api/services/daptiles/index.html +1 -1
  251. package/coverage/lcov-report/map/api/services/features/features.hooks.js.html +114 -183
  252. package/coverage/lcov-report/map/api/services/features/features.service.js.html +56 -359
  253. package/coverage/lcov-report/map/api/services/features/index.html +31 -31
  254. package/coverage/lcov-report/map/api/services/index.html +21 -21
  255. package/coverage/lcov-report/map/api/services/index.js.html +258 -495
  256. package/coverage/lcov-report/map/api/services/projects/index.html +21 -21
  257. package/coverage/lcov-report/map/api/services/projects/projects.hooks.js.html +237 -237
  258. package/coverage/lcov-report/map/common/dynamic-grid-source.js.html +68 -68
  259. package/coverage/lcov-report/map/common/errors.js.html +16 -16
  260. package/coverage/lcov-report/map/common/geotiff-grid-source.js.html +267 -270
  261. package/coverage/lcov-report/map/common/grid.js.html +554 -554
  262. package/coverage/lcov-report/map/common/index.html +158 -158
  263. package/coverage/lcov-report/map/common/index.js.html +68 -68
  264. package/coverage/lcov-report/map/common/meteo-model-grid-source.js.html +73 -73
  265. package/coverage/lcov-report/map/common/moment-utils.js.html +18 -18
  266. package/coverage/lcov-report/map/common/opendap-grid-source.js.html +484 -484
  267. package/coverage/lcov-report/map/common/opendap-utils.js.html +353 -353
  268. package/coverage/lcov-report/map/common/permissions.js.html +36 -42
  269. package/coverage/lcov-report/map/common/time-based-grid-source.js.html +59 -59
  270. package/coverage/lcov-report/map/common/tms-utils.js.html +6 -6
  271. package/coverage/lcov-report/map/common/wcs-grid-source.js.html +190 -190
  272. package/coverage/lcov-report/map/common/wcs-utils.js.html +339 -339
  273. package/coverage/lcov-report/map/common/weacast-grid-source.js.html +345 -345
  274. package/coverage/lcov-report/map/common/wfs-utils.js.html +11 -11
  275. package/coverage/lcov-report/map/common/wms-utils.js.html +8 -8
  276. package/coverage/lcov-report/map/common/wmts-utils.js.html +7 -7
  277. package/coverage/lcov.info +7793 -8564
  278. package/coverage/map/api/hooks/hooks.catalog.js.html +257 -353
  279. package/coverage/map/api/hooks/hooks.features.js.html +218 -218
  280. package/coverage/map/api/hooks/hooks.query.js.html +810 -795
  281. package/coverage/map/api/hooks/index.html +54 -54
  282. package/coverage/map/api/hooks/index.js.html +16 -16
  283. package/coverage/map/api/index.html +32 -32
  284. package/coverage/map/api/index.js.html +46 -46
  285. package/coverage/map/api/marshall.js.html +72 -72
  286. package/coverage/map/api/models/alerts.model.mongodb.js.html +24 -24
  287. package/coverage/map/api/models/catalog.model.mongodb.js.html +27 -69
  288. package/coverage/map/api/models/features.model.mongodb.js.html +80 -80
  289. package/coverage/map/api/models/index.html +54 -69
  290. package/coverage/map/api/models/projects.model.mongodb.js.html +26 -26
  291. package/coverage/map/api/services/alerts/alerts.hooks.js.html +136 -136
  292. package/coverage/map/api/services/alerts/alerts.service.js.html +343 -343
  293. package/coverage/map/api/services/alerts/index.html +32 -32
  294. package/coverage/map/api/services/catalog/catalog.hooks.js.html +160 -178
  295. package/coverage/map/api/services/catalog/index.html +21 -21
  296. package/coverage/map/api/services/daptiles/daptiles.service.js.html +1 -1
  297. package/coverage/map/api/services/daptiles/index.html +1 -1
  298. package/coverage/map/api/services/features/features.hooks.js.html +114 -183
  299. package/coverage/map/api/services/features/features.service.js.html +56 -359
  300. package/coverage/map/api/services/features/index.html +31 -31
  301. package/coverage/map/api/services/index.html +21 -21
  302. package/coverage/map/api/services/index.js.html +258 -495
  303. package/coverage/map/api/services/projects/index.html +21 -21
  304. package/coverage/map/api/services/projects/projects.hooks.js.html +237 -237
  305. package/coverage/map/common/dynamic-grid-source.js.html +68 -68
  306. package/coverage/map/common/errors.js.html +16 -16
  307. package/coverage/map/common/geotiff-grid-source.js.html +267 -270
  308. package/coverage/map/common/grid.js.html +554 -554
  309. package/coverage/map/common/index.html +158 -158
  310. package/coverage/map/common/index.js.html +68 -68
  311. package/coverage/map/common/meteo-model-grid-source.js.html +73 -73
  312. package/coverage/map/common/moment-utils.js.html +18 -18
  313. package/coverage/map/common/opendap-grid-source.js.html +484 -484
  314. package/coverage/map/common/opendap-utils.js.html +353 -353
  315. package/coverage/map/common/permissions.js.html +36 -42
  316. package/coverage/map/common/time-based-grid-source.js.html +59 -59
  317. package/coverage/map/common/tms-utils.js.html +6 -6
  318. package/coverage/map/common/wcs-grid-source.js.html +190 -190
  319. package/coverage/map/common/wcs-utils.js.html +339 -339
  320. package/coverage/map/common/weacast-grid-source.js.html +345 -345
  321. package/coverage/map/common/wfs-utils.js.html +11 -11
  322. package/coverage/map/common/wms-utils.js.html +8 -8
  323. package/coverage/map/common/wmts-utils.js.html +7 -7
  324. package/coverage/tmp/coverage-151166-1723543324307-0.json +1 -0
  325. package/coverage/tmp/coverage-151178-1723543324283-0.json +1 -0
  326. package/coverage/tmp/coverage-151189-1723543324271-0.json +1 -0
  327. package/coverage/tmp/coverage-151201-1723543324248-0.json +1 -0
  328. package/coverage/tmp/coverage-151208-1723543324227-0.json +1 -0
  329. package/extras/configs/panes.top.js +33 -11
  330. package/extras/configs/stickies.js +26 -16
  331. package/extras/configs/widgets.left.js +13 -1
  332. package/extras/libs/jsts.min.js +8 -0
  333. package/{test/client/core/account.js → extras/tests/core/account.mjs} +4 -4
  334. package/extras/tests/core/api.mjs +114 -0
  335. package/{test/client/core/collection.js → extras/tests/core/collection.mjs} +8 -8
  336. package/{test/client/core/dialogs.js → extras/tests/core/dialogs.mjs} +1 -1
  337. package/extras/tests/core/index.mjs +9 -0
  338. package/{test/client/core/layout.js → extras/tests/core/layout.mjs} +7 -3
  339. package/{test/client/core/runner.js → extras/tests/core/runner.mjs} +3 -3
  340. package/{test/client/core/screens.js → extras/tests/core/screens.mjs} +1 -1
  341. package/{test/client/core/utils.js → extras/tests/core/utils.mjs} +79 -26
  342. package/extras/tests/index.mjs +4 -0
  343. package/{test/client/map/api.js → extras/tests/map/api.mjs} +1 -1
  344. package/{test/client/map/catalog.js → extras/tests/map/catalog.mjs} +18 -18
  345. package/{test/client/map/controls.js → extras/tests/map/controls.mjs} +3 -3
  346. package/extras/tests/map/index.mjs +5 -0
  347. package/{test/client/map/time.js → extras/tests/map/time.mjs} +3 -3
  348. package/{test/client/map/utils.js → extras/tests/map/utils.mjs} +6 -5
  349. package/extras/tours/fab.js +36 -0
  350. package/extras/tours/layout.js +49 -0
  351. package/extras/tours/pane.left.js +78 -0
  352. package/extras/tours/pane.right.js +145 -0
  353. package/extras/tours/pane.top.js +239 -0
  354. package/map/api/config/layers.cjs +28 -13
  355. package/map/api/hooks/hooks.query.js +12 -7
  356. package/map/api/models/catalog.model.mongodb.js +17 -6
  357. package/map/api/services/catalog/catalog.hooks.js +1 -1
  358. package/map/api/services/index.js +18 -1
  359. package/map/client/cesium/utils/utils.cesium.js +25 -65
  360. package/map/client/cesium/utils/utils.features.js +1 -0
  361. package/map/client/cesium/utils/utils.geojson.js +1 -0
  362. package/map/client/cesium/utils/utils.style.js +7 -6
  363. package/map/client/components/KFeatureEditor.vue +3 -3
  364. package/map/client/components/KFeaturesChart.vue +4 -4
  365. package/map/client/components/KFeaturesFilterEditor.vue +19 -13
  366. package/map/client/components/KFeaturesFilterManager.vue +7 -4
  367. package/map/client/components/KFeaturesTable.vue +2 -2
  368. package/map/client/components/KLayerEditor.vue +6 -6
  369. package/map/client/components/KMeasureTool.vue +2 -1
  370. package/map/client/components/catalog/KBaseLayersSelector.vue +1 -1
  371. package/map/client/components/catalog/KCategoryItem.vue +15 -1
  372. package/map/client/components/catalog/KConnectLayer.vue +2 -2
  373. package/map/client/components/catalog/KCreateView.vue +3 -2
  374. package/map/client/components/catalog/KFilteredLayerItem.vue +26 -6
  375. package/map/client/components/catalog/KImportLayer.vue +6 -3
  376. package/map/client/components/catalog/KLayerCategories.vue +6 -6
  377. package/map/client/components/catalog/KLayerItem.vue +12 -2
  378. package/map/client/components/catalog/KLayersList.vue +180 -0
  379. package/map/client/components/catalog/KLayersPanel.vue +146 -36
  380. package/map/client/components/catalog/KLayersSelector.vue +96 -48
  381. package/map/client/components/catalog/KProjectEditor.vue +0 -9
  382. package/map/client/components/catalog/KProjectSelector.vue +3 -2
  383. package/map/client/components/catalog/KProjectsPanel.vue +23 -8
  384. package/map/client/components/catalog/KViewsPanel.vue +18 -8
  385. package/map/client/components/catalog/KWeatherLayersSelector.vue +3 -3
  386. package/map/client/components/form/KDirectionField.vue +3 -6
  387. package/map/client/components/form/KLayerCategoryField.vue +2 -2
  388. package/map/client/components/form/KOwsServiceField.vue +25 -24
  389. package/map/client/components/form/KSelectLayersField.vue +4 -4
  390. package/map/client/components/form/KSelectViewsField.vue +4 -4
  391. package/map/client/components/legend/KLayerLegend.vue +11 -2
  392. package/map/client/components/legend/KLegend.vue +44 -51
  393. package/map/client/components/location/KLocationCardSection.vue +6 -7
  394. package/map/client/components/location/KLocationMap.vue +23 -13
  395. package/map/client/components/stickies/KPosition.vue +5 -0
  396. package/map/client/components/stickies/KZoomControl.vue +70 -0
  397. package/map/client/components/styles/KLayerStyleAction.vue +59 -12
  398. package/map/client/components/styles/KStyleEditor.vue +71 -8
  399. package/map/client/components/styles/KStyleEditorSection.vue +82 -33
  400. package/map/client/components/styles/KStyleManager.vue +119 -59
  401. package/map/client/components/styles/KStylePreview.vue +9 -25
  402. package/map/client/components/styles/KStylePreviewItem.vue +22 -1
  403. package/map/client/components/tools/KSearchTool.vue +1 -1
  404. package/map/client/components/widget/KElevationProfile.vue +20 -17
  405. package/map/client/components/widget/KInformationBox.vue +5 -5
  406. package/map/client/components/widget/KMapillaryViewer.vue +2 -1
  407. package/map/client/components/widget/KTimeSeries.vue +11 -9
  408. package/map/client/globe.js +2 -0
  409. package/map/client/i18n/map_en.json +30 -7
  410. package/map/client/i18n/map_fr.json +30 -7
  411. package/map/client/leaflet/GradientPath.js +61 -24
  412. package/map/client/leaflet/ShapeMarker.js +12 -5
  413. package/map/client/leaflet/TiledMeshLayer.js +3 -3
  414. package/map/client/leaflet/utils/utils.geojson.js +66 -8
  415. package/map/client/leaflet/utils/utils.style.js +14 -15
  416. package/map/client/mixins/globe/mixin.base-globe.js +190 -34
  417. package/map/client/mixins/globe/mixin.file-layers.js +3 -0
  418. package/map/client/mixins/globe/mixin.geojson-layers.js +179 -31
  419. package/map/client/mixins/globe/mixin.opendap-layers.js +2 -1
  420. package/map/client/mixins/globe/mixin.style.js +23 -1
  421. package/map/client/mixins/globe/mixin.tooltip.js +14 -2
  422. package/map/client/mixins/map/mixin.base-map.js +156 -58
  423. package/map/client/mixins/map/mixin.edit-layers.js +18 -15
  424. package/map/client/mixins/map/mixin.geojson-layers.js +181 -106
  425. package/map/client/mixins/map/mixin.heatmap-layers.js +3 -2
  426. package/map/client/mixins/map/mixin.map-activity.js +6 -1
  427. package/map/client/mixins/map/mixin.mapillary-layers.js +2 -1
  428. package/map/client/mixins/map/mixin.pmtiles-layers.js +3 -3
  429. package/map/client/mixins/map/mixin.tiled-mesh-layers.js +3 -2
  430. package/map/client/mixins/map/mixin.tiled-wind-layers.js +3 -2
  431. package/map/client/mixins/mixin.activity.js +199 -55
  432. package/map/client/mixins/mixin.context.js +11 -11
  433. package/map/client/mixins/mixin.feature-service.js +11 -9
  434. package/map/client/mixins/mixin.weacast.js +5 -3
  435. package/map/client/readers/reader.geojson.js +3 -1
  436. package/map/client/utils/utils.capture.js +3 -3
  437. package/map/client/utils/utils.catalog.js +9 -5
  438. package/map/client/utils/utils.features.js +120 -54
  439. package/map/client/utils/utils.js +25 -10
  440. package/map/client/utils/utils.layers.js +148 -24
  441. package/map/client/utils/utils.location.js +26 -9
  442. package/map/client/utils/utils.schema.js +2 -1
  443. package/map/client/utils/utils.style.js +53 -9
  444. package/map/common/geotiff-grid-source.js +1 -3
  445. package/map/common/opendap-utils.js +0 -1
  446. package/map/common/tms-utils.js +0 -1
  447. package/map/common/wcs-utils.js +0 -1
  448. package/map/common/wfs-utils.js +0 -1
  449. package/map/common/wms-utils.js +7 -1
  450. package/map/common/wmts-utils.js +0 -1
  451. package/package.json +12 -12
  452. package/scripts/init_runner.sh +3 -3
  453. package/scripts/kash/CHANGELOG.md +27 -0
  454. package/scripts/kash/kash.sh +556 -237
  455. package/scripts/kash/scripts/run_tests.sh +44 -5
  456. package/scripts/setup_workspace.sh +23 -13
  457. package/test/api/core/config/default.cjs +2 -1
  458. package/test/api/core/tags.test.js +62 -0
  459. package/test/api/core/test-log-2024-04-22.log +84 -0
  460. package/test/api/core/{test-log-2025-02-05.log → test-log-2024-04-23.log} +3 -3
  461. package/test/api/core/test-log-2024-08-13.log +3 -0
  462. package/test/api/map/config/default.cjs +2 -1
  463. package/test/api/map/config/layers.json +9 -0
  464. package/test/api/map/data/openradiation.json +13811 -0
  465. package/test/api/map/grid-sources.test.js +1 -3
  466. package/test/api/map/index.test.js +60 -1
  467. package/test/api/map/style.test.js +30 -1
  468. package/test/api/map/test-log-2025-03-08.log +0 -0
  469. package/test.api.js +1 -1
  470. package/vite/App.vue +18 -0
  471. package/vite/AppWithGlobe.vue +84 -0
  472. package/vite/GlobeActivity.vue +58 -0
  473. package/vite/MapActivity.vue +63 -0
  474. package/vite/MapActivityWithGlobe.vue +63 -0
  475. package/vite/README.md +169 -0
  476. package/vite/config.js +221 -0
  477. package/vite/index_with_globe.html +50 -0
  478. package/vite/index_with_map.html +50 -0
  479. package/vite/package.json +173 -0
  480. package/vite/quasar.variables.scss +17 -0
  481. package/vite/vite.config.js +166 -0
  482. package/vite/yarn.lock +11641 -0
  483. package/core/client/components/media/KImageViewer.vue +0 -68
  484. package/core/client/components/media/KMarkdownViewer.vue +0 -55
  485. package/core/client/components/media/KMediaBrowser.vue +0 -301
  486. package/coverage/core/api/services/users/users.service.js.html +0 -100
  487. package/coverage/core/common/utils.offline.js.html +0 -199
  488. package/coverage/lcov-report/core/api/services/users/users.service.js.html +0 -100
  489. package/coverage/lcov-report/core/common/utils.offline.js.html +0 -199
  490. package/coverage/lcov-report/map/api/models/styles.model.mongodb.js.html +0 -112
  491. package/coverage/lcov-report/map/api/services/styles/index.html +0 -116
  492. package/coverage/lcov-report/map/api/services/styles/styles.hooks.js.html +0 -196
  493. package/coverage/map/api/models/styles.model.mongodb.js.html +0 -112
  494. package/coverage/map/api/services/styles/index.html +0 -116
  495. package/coverage/map/api/services/styles/styles.hooks.js.html +0 -196
  496. package/coverage/tmp/coverage-151198-1753351220086-0.json +0 -1
  497. package/coverage/tmp/coverage-151210-1753351220070-0.json +0 -1
  498. package/coverage/tmp/coverage-151221-1753351129816-0.json +0 -1
  499. package/coverage/tmp/coverage-151233-1753351129803-0.json +0 -1
  500. package/coverage/tmp/coverage-151240-1753351129770-0.json +0 -1
  501. package/coverage/tmp/coverage-151307-1753351220058-0.json +0 -1
  502. package/coverage/tmp/coverage-151319-1753351220044-0.json +0 -1
  503. package/coverage/tmp/coverage-151326-1753351220010-0.json +0 -1
  504. package/extras/tours/core/account-profile.js +0 -32
  505. package/extras/tours/core/account.js +0 -143
  506. package/extras/tours/core/add-member.js +0 -75
  507. package/extras/tours/core/add-tag.js +0 -13
  508. package/extras/tours/core/create-group.js +0 -19
  509. package/extras/tours/core/create-organisation.js +0 -19
  510. package/extras/tours/core/create-tag.js +0 -26
  511. package/extras/tours/core/edit-member-role.js +0 -13
  512. package/extras/tours/core/groups.js +0 -65
  513. package/extras/tours/core/join-group.js +0 -13
  514. package/extras/tours/core/login.js +0 -41
  515. package/extras/tours/core/members.js +0 -108
  516. package/extras/tours/core/register.js +0 -61
  517. package/extras/tours/core/send-reset-password.js +0 -14
  518. package/extras/tours/core/tags.js +0 -65
  519. package/extras/tours/map/catalog-panel.js +0 -112
  520. package/extras/tours/map/fab.js +0 -26
  521. package/extras/tours/map/navigation-bar.js +0 -187
  522. package/extras/tours/map/side-nav.js +0 -36
  523. package/test/api/core/test-log-2025-05-21.log +0 -15
  524. package/test/api/core/test-log-2025-06-25.log +0 -9
  525. package/test/api/core/test-log-2025-07-24.log +0 -44
  526. package/test/api/map/test-log-2025-05-27.log +0 -13
  527. package/test/api/map/test-log-2025-06-23.log +0 -7
  528. package/test/api/map/test-log-2025-07-24.log +0 -11
  529. package/test/client/core/api.js +0 -361
  530. package/test/client/core/index.js +0 -9
  531. package/test/client/index.js +0 -4
  532. package/test/client/map/index.js +0 -5
  533. package/test.client.js +0 -1
  534. /package/{test/client/core/time.js → extras/tests/core/time.mjs} +0 -0
  535. /package/extras/tours/{map/add-layer.js → add-layer.js} +0 -0
  536. /package/extras/tours/{map/catalog-categories.js → catalog-categories.js} +0 -0
  537. /package/extras/tours/{map/connect-layer.js → connect-layer.js} +0 -0
  538. /package/extras/tours/{map/create-layer.js → create-layer.js} +0 -0
  539. /package/extras/tours/{map/create-view.js → create-view.js} +0 -0
  540. /package/extras/tours/{map/import-layer.js → import-layer.js} +0 -0
  541. /package/extras/tours/{map/timeline.js → pane.bottom.js} +0 -0
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">70.83% </span>
26
+ <span class="strong">30.21% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>153/216</span>
28
+ <span class='fraction'>97/321</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">68.18% </span>
33
+ <span class="strong">100% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>15/22</span>
35
+ <span class='fraction'>3/3</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">47.05% </span>
40
+ <span class="strong">3.7% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>8/17</span>
42
+ <span class='fraction'>1/27</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">70.83% </span>
47
+ <span class="strong">30.21% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>153/216</span>
49
+ <span class='fraction'>97/321</span>
50
50
  </div>
51
51
 
52
52
 
@@ -61,7 +61,7 @@
61
61
  </div>
62
62
  </template>
63
63
  </div>
64
- <div class='status-line medium'></div>
64
+ <div class='status-line low'></div>
65
65
  <pre><table class="coverage">
66
66
  <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
67
  <a name='L2'></a><a href='#L2'>2</a>
@@ -279,149 +279,318 @@
279
279
  <a name='L214'></a><a href='#L214'>214</a>
280
280
  <a name='L215'></a><a href='#L215'>215</a>
281
281
  <a name='L216'></a><a href='#L216'>216</a>
282
- <a name='L217'></a><a href='#L217'>217</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">2x</span>
283
- <span class="cline-any cline-yes">2x</span>
284
- <span class="cline-any cline-yes">2x</span>
285
- <span class="cline-any cline-yes">2x</span>
286
- <span class="cline-any cline-yes">2x</span>
287
- <span class="cline-any cline-yes">2x</span>
288
- <span class="cline-any cline-yes">2x</span>
289
- <span class="cline-any cline-yes">2x</span>
290
- <span class="cline-any cline-yes">2x</span>
291
- <span class="cline-any cline-yes">2x</span>
292
- <span class="cline-any cline-yes">2x</span>
293
- <span class="cline-any cline-yes">2x</span>
294
- <span class="cline-any cline-yes">2x</span>
295
- <span class="cline-any cline-yes">2x</span>
296
- <span class="cline-any cline-yes">2x</span>
297
- <span class="cline-any cline-yes">2x</span>
298
- <span class="cline-any cline-yes">2x</span>
299
- <span class="cline-any cline-yes">2x</span>
300
- <span class="cline-any cline-yes">2x</span>
301
- <span class="cline-any cline-yes">2x</span>
302
- <span class="cline-any cline-yes">2x</span>
303
- <span class="cline-any cline-yes">2x</span>
304
- <span class="cline-any cline-yes">2x</span>
305
- <span class="cline-any cline-yes">2x</span>
306
- <span class="cline-any cline-yes">2x</span>
307
- <span class="cline-any cline-yes">2x</span>
308
- <span class="cline-any cline-yes">2x</span>
309
- <span class="cline-any cline-yes">2x</span>
310
- <span class="cline-any cline-yes">2x</span>
311
- <span class="cline-any cline-yes">2x</span>
312
- <span class="cline-any cline-yes">2x</span>
313
- <span class="cline-any cline-yes">2x</span>
314
- <span class="cline-any cline-no">&nbsp;</span>
315
- <span class="cline-any cline-no">&nbsp;</span>
316
- <span class="cline-any cline-no">&nbsp;</span>
317
- <span class="cline-any cline-no">&nbsp;</span>
318
- <span class="cline-any cline-no">&nbsp;</span>
319
- <span class="cline-any cline-no">&nbsp;</span>
320
- <span class="cline-any cline-no">&nbsp;</span>
321
- <span class="cline-any cline-no">&nbsp;</span>
322
- <span class="cline-any cline-no">&nbsp;</span>
323
- <span class="cline-any cline-no">&nbsp;</span>
324
- <span class="cline-any cline-no">&nbsp;</span>
325
- <span class="cline-any cline-no">&nbsp;</span>
326
- <span class="cline-any cline-no">&nbsp;</span>
327
- <span class="cline-any cline-yes">2x</span>
328
- <span class="cline-any cline-yes">2x</span>
329
- <span class="cline-any cline-yes">2x</span>
330
- <span class="cline-any cline-yes">26x</span>
331
- <span class="cline-any cline-yes">26x</span>
332
- <span class="cline-any cline-yes">26x</span>
333
- <span class="cline-any cline-yes">26x</span>
334
- <span class="cline-any cline-yes">26x</span>
335
- <span class="cline-any cline-yes">26x</span>
336
- <span class="cline-any cline-yes">26x</span>
337
- <span class="cline-any cline-yes">26x</span>
338
- <span class="cline-any cline-yes">26x</span>
339
- <span class="cline-any cline-yes">26x</span>
340
- <span class="cline-any cline-yes">26x</span>
341
- <span class="cline-any cline-yes">26x</span>
342
- <span class="cline-any cline-yes">26x</span>
343
- <span class="cline-any cline-yes">23x</span>
344
- <span class="cline-any cline-yes">23x</span>
345
- <span class="cline-any cline-yes">23x</span>
346
- <span class="cline-any cline-yes">23x</span>
347
- <span class="cline-any cline-yes">23x</span>
348
- <span class="cline-any cline-yes">23x</span>
349
- <span class="cline-any cline-yes">23x</span>
350
- <span class="cline-any cline-yes">23x</span>
351
- <span class="cline-any cline-yes">23x</span>
352
- <span class="cline-any cline-yes">23x</span>
353
- <span class="cline-any cline-yes">23x</span>
354
- <span class="cline-any cline-yes">23x</span>
355
- <span class="cline-any cline-yes">23x</span>
356
- <span class="cline-any cline-yes">23x</span>
357
- <span class="cline-any cline-yes">23x</span>
358
- <span class="cline-any cline-yes">23x</span>
359
- <span class="cline-any cline-yes">23x</span>
360
- <span class="cline-any cline-yes">23x</span>
361
- <span class="cline-any cline-yes">23x</span>
362
- <span class="cline-any cline-yes">26x</span>
363
- <span class="cline-any cline-yes">2x</span>
364
- <span class="cline-any cline-yes">2x</span>
365
- <span class="cline-any cline-yes">2x</span>
366
- <span class="cline-any cline-yes">26x</span>
367
- <span class="cline-any cline-yes">26x</span>
368
- <span class="cline-any cline-yes">26x</span>
369
- <span class="cline-any cline-yes">26x</span>
370
- <span class="cline-any cline-yes">46x</span>
371
- <span class="cline-any cline-yes">26x</span>
372
- <span class="cline-any cline-yes">26x</span>
373
- <span class="cline-any cline-yes">26x</span>
374
- <span class="cline-any cline-yes">26x</span>
375
- <span class="cline-any cline-yes">26x</span>
376
- <span class="cline-any cline-yes">26x</span>
377
- <span class="cline-any cline-yes">7x</span>
378
- <span class="cline-any cline-no">&nbsp;</span>
379
- <span class="cline-any cline-no">&nbsp;</span>
380
- <span class="cline-any cline-yes">7x</span>
381
- <span class="cline-any cline-yes">26x</span>
382
- <span class="cline-any cline-yes">26x</span>
383
- <span class="cline-any cline-yes">26x</span>
384
- <span class="cline-any cline-yes">26x</span>
385
- <span class="cline-any cline-yes">2x</span>
386
- <span class="cline-any cline-yes">2x</span>
387
- <span class="cline-any cline-yes">14x</span>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
388
+ <span class="cline-any cline-yes">1x</span>
389
+ <span class="cline-any cline-yes">1x</span>
390
+ <span class="cline-any cline-yes">1x</span>
391
+ <span class="cline-any cline-yes">1x</span>
392
+ <span class="cline-any cline-yes">1x</span>
393
+ <span class="cline-any cline-yes">1x</span>
394
+ <span class="cline-any cline-yes">1x</span>
395
+ <span class="cline-any cline-yes">1x</span>
396
+ <span class="cline-any cline-yes">1x</span>
397
+ <span class="cline-any cline-yes">1x</span>
398
+ <span class="cline-any cline-yes">1x</span>
399
+ <span class="cline-any cline-yes">1x</span>
400
+ <span class="cline-any cline-yes">1x</span>
401
+ <span class="cline-any cline-yes">1x</span>
402
+ <span class="cline-any cline-yes">1x</span>
403
+ <span class="cline-any cline-yes">1x</span>
404
+ <span class="cline-any cline-yes">1x</span>
405
+ <span class="cline-any cline-yes">1x</span>
406
+ <span class="cline-any cline-yes">1x</span>
407
+ <span class="cline-any cline-yes">1x</span>
408
+ <span class="cline-any cline-yes">1x</span>
409
+ <span class="cline-any cline-yes">1x</span>
410
+ <span class="cline-any cline-yes">1x</span>
411
+ <span class="cline-any cline-yes">1x</span>
412
+ <span class="cline-any cline-yes">1x</span>
413
+ <span class="cline-any cline-yes">1x</span>
414
+ <span class="cline-any cline-yes">1x</span>
415
+ <span class="cline-any cline-yes">1x</span>
416
+ <span class="cline-any cline-yes">1x</span>
417
+ <span class="cline-any cline-yes">1x</span>
418
+ <span class="cline-any cline-yes">1x</span>
419
+ <span class="cline-any cline-no">&nbsp;</span>
420
+ <span class="cline-any cline-no">&nbsp;</span>
421
+ <span class="cline-any cline-no">&nbsp;</span>
422
+ <span class="cline-any cline-no">&nbsp;</span>
423
+ <span class="cline-any cline-no">&nbsp;</span>
424
+ <span class="cline-any cline-no">&nbsp;</span>
425
+ <span class="cline-any cline-no">&nbsp;</span>
426
+ <span class="cline-any cline-no">&nbsp;</span>
427
+ <span class="cline-any cline-no">&nbsp;</span>
428
+ <span class="cline-any cline-no">&nbsp;</span>
429
+ <span class="cline-any cline-no">&nbsp;</span>
430
+ <span class="cline-any cline-no">&nbsp;</span>
431
+ <span class="cline-any cline-no">&nbsp;</span>
432
+ <span class="cline-any cline-yes">1x</span>
433
+ <span class="cline-any cline-yes">1x</span>
434
+ <span class="cline-any cline-yes">1x</span>
435
+ <span class="cline-any cline-no">&nbsp;</span>
436
+ <span class="cline-any cline-no">&nbsp;</span>
437
+ <span class="cline-any cline-no">&nbsp;</span>
438
+ <span class="cline-any cline-no">&nbsp;</span>
439
+ <span class="cline-any cline-no">&nbsp;</span>
440
+ <span class="cline-any cline-no">&nbsp;</span>
441
+ <span class="cline-any cline-no">&nbsp;</span>
442
+ <span class="cline-any cline-no">&nbsp;</span>
443
+ <span class="cline-any cline-no">&nbsp;</span>
444
+ <span class="cline-any cline-no">&nbsp;</span>
445
+ <span class="cline-any cline-no">&nbsp;</span>
446
+ <span class="cline-any cline-no">&nbsp;</span>
447
+ <span class="cline-any cline-no">&nbsp;</span>
448
+ <span class="cline-any cline-no">&nbsp;</span>
449
+ <span class="cline-any cline-no">&nbsp;</span>
450
+ <span class="cline-any cline-no">&nbsp;</span>
451
+ <span class="cline-any cline-no">&nbsp;</span>
452
+ <span class="cline-any cline-no">&nbsp;</span>
453
+ <span class="cline-any cline-no">&nbsp;</span>
454
+ <span class="cline-any cline-no">&nbsp;</span>
455
+ <span class="cline-any cline-no">&nbsp;</span>
456
+ <span class="cline-any cline-no">&nbsp;</span>
457
+ <span class="cline-any cline-no">&nbsp;</span>
458
+ <span class="cline-any cline-no">&nbsp;</span>
459
+ <span class="cline-any cline-no">&nbsp;</span>
460
+ <span class="cline-any cline-no">&nbsp;</span>
461
+ <span class="cline-any cline-no">&nbsp;</span>
462
+ <span class="cline-any cline-no">&nbsp;</span>
463
+ <span class="cline-any cline-no">&nbsp;</span>
464
+ <span class="cline-any cline-no">&nbsp;</span>
465
+ <span class="cline-any cline-no">&nbsp;</span>
466
+ <span class="cline-any cline-no">&nbsp;</span>
467
+ <span class="cline-any cline-no">&nbsp;</span>
468
+ <span class="cline-any cline-yes">1x</span>
469
+ <span class="cline-any cline-yes">1x</span>
470
+ <span class="cline-any cline-yes">1x</span>
471
+ <span class="cline-any cline-no">&nbsp;</span>
472
+ <span class="cline-any cline-no">&nbsp;</span>
473
+ <span class="cline-any cline-no">&nbsp;</span>
474
+ <span class="cline-any cline-no">&nbsp;</span>
475
+ <span class="cline-any cline-no">&nbsp;</span>
476
+ <span class="cline-any cline-no">&nbsp;</span>
477
+ <span class="cline-any cline-no">&nbsp;</span>
478
+ <span class="cline-any cline-no">&nbsp;</span>
479
+ <span class="cline-any cline-no">&nbsp;</span>
480
+ <span class="cline-any cline-no">&nbsp;</span>
481
+ <span class="cline-any cline-no">&nbsp;</span>
482
+ <span class="cline-any cline-no">&nbsp;</span>
483
+ <span class="cline-any cline-no">&nbsp;</span>
484
+ <span class="cline-any cline-no">&nbsp;</span>
485
+ <span class="cline-any cline-no">&nbsp;</span>
486
+ <span class="cline-any cline-no">&nbsp;</span>
487
+ <span class="cline-any cline-no">&nbsp;</span>
488
+ <span class="cline-any cline-no">&nbsp;</span>
489
+ <span class="cline-any cline-no">&nbsp;</span>
490
+ <span class="cline-any cline-yes">1x</span>
491
+ <span class="cline-any cline-yes">1x</span>
388
492
  <span class="cline-any cline-yes">8x</span>
493
+ <span class="cline-any cline-yes">3x</span>
494
+ <span class="cline-any cline-yes">3x</span>
389
495
  <span class="cline-any cline-yes">8x</span>
390
- <span class="cline-any cline-yes">14x</span>
391
- <span class="cline-any cline-yes">2x</span>
392
- <span class="cline-any cline-yes">2x</span>
496
+ <span class="cline-any cline-yes">1x</span>
497
+ <span class="cline-any cline-yes">1x</span>
498
+ <span class="cline-any cline-no">&nbsp;</span>
499
+ <span class="cline-any cline-no">&nbsp;</span>
500
+ <span class="cline-any cline-yes">1x</span>
501
+ <span class="cline-any cline-yes">1x</span>
502
+ <span class="cline-any cline-no">&nbsp;</span>
503
+ <span class="cline-any cline-no">&nbsp;</span>
504
+ <span class="cline-any cline-no">&nbsp;</span>
505
+ <span class="cline-any cline-no">&nbsp;</span>
506
+ <span class="cline-any cline-no">&nbsp;</span>
507
+ <span class="cline-any cline-no">&nbsp;</span>
508
+ <span class="cline-any cline-no">&nbsp;</span>
509
+ <span class="cline-any cline-no">&nbsp;</span>
510
+ <span class="cline-any cline-no">&nbsp;</span>
511
+ <span class="cline-any cline-no">&nbsp;</span>
512
+ <span class="cline-any cline-yes">1x</span>
513
+ <span class="cline-any cline-yes">1x</span>
514
+ <span class="cline-any cline-no">&nbsp;</span>
515
+ <span class="cline-any cline-no">&nbsp;</span>
516
+ <span class="cline-any cline-no">&nbsp;</span>
517
+ <span class="cline-any cline-no">&nbsp;</span>
518
+ <span class="cline-any cline-no">&nbsp;</span>
519
+ <span class="cline-any cline-no">&nbsp;</span>
520
+ <span class="cline-any cline-no">&nbsp;</span>
521
+ <span class="cline-any cline-no">&nbsp;</span>
522
+ <span class="cline-any cline-no">&nbsp;</span>
523
+ <span class="cline-any cline-no">&nbsp;</span>
524
+ <span class="cline-any cline-no">&nbsp;</span>
525
+ <span class="cline-any cline-yes">1x</span>
526
+ <span class="cline-any cline-yes">1x</span>
527
+ <span class="cline-any cline-yes">1x</span>
528
+ <span class="cline-any cline-no">&nbsp;</span>
529
+ <span class="cline-any cline-no">&nbsp;</span>
530
+ <span class="cline-any cline-no">&nbsp;</span>
531
+ <span class="cline-any cline-no">&nbsp;</span>
532
+ <span class="cline-any cline-no">&nbsp;</span>
533
+ <span class="cline-any cline-no">&nbsp;</span>
534
+ <span class="cline-any cline-no">&nbsp;</span>
535
+ <span class="cline-any cline-no">&nbsp;</span>
536
+ <span class="cline-any cline-no">&nbsp;</span>
537
+ <span class="cline-any cline-no">&nbsp;</span>
538
+ <span class="cline-any cline-no">&nbsp;</span>
539
+ <span class="cline-any cline-no">&nbsp;</span>
540
+ <span class="cline-any cline-no">&nbsp;</span>
541
+ <span class="cline-any cline-no">&nbsp;</span>
542
+ <span class="cline-any cline-no">&nbsp;</span>
543
+ <span class="cline-any cline-no">&nbsp;</span>
544
+ <span class="cline-any cline-no">&nbsp;</span>
545
+ <span class="cline-any cline-no">&nbsp;</span>
546
+ <span class="cline-any cline-no">&nbsp;</span>
547
+ <span class="cline-any cline-yes">1x</span>
548
+ <span class="cline-any cline-yes">1x</span>
549
+ <span class="cline-any cline-yes">1x</span>
550
+ <span class="cline-any cline-yes">1x</span>
551
+ <span class="cline-any cline-no">&nbsp;</span>
552
+ <span class="cline-any cline-no">&nbsp;</span>
553
+ <span class="cline-any cline-no">&nbsp;</span>
554
+ <span class="cline-any cline-no">&nbsp;</span>
555
+ <span class="cline-any cline-no">&nbsp;</span>
556
+ <span class="cline-any cline-no">&nbsp;</span>
557
+ <span class="cline-any cline-no">&nbsp;</span>
558
+ <span class="cline-any cline-yes">1x</span>
559
+ <span class="cline-any cline-no">&nbsp;</span>
560
+ <span class="cline-any cline-no">&nbsp;</span>
561
+ <span class="cline-any cline-no">&nbsp;</span>
562
+ <span class="cline-any cline-no">&nbsp;</span>
563
+ <span class="cline-any cline-no">&nbsp;</span>
564
+ <span class="cline-any cline-no">&nbsp;</span>
565
+ <span class="cline-any cline-no">&nbsp;</span>
566
+ <span class="cline-any cline-yes">1x</span>
567
+ <span class="cline-any cline-yes">1x</span>
568
+ <span class="cline-any cline-no">&nbsp;</span>
569
+ <span class="cline-any cline-no">&nbsp;</span>
570
+ <span class="cline-any cline-no">&nbsp;</span>
393
571
  <span class="cline-any cline-no">&nbsp;</span>
394
572
  <span class="cline-any cline-no">&nbsp;</span>
395
- <span class="cline-any cline-yes">2x</span>
396
- <span class="cline-any cline-yes">2x</span>
397
- <span class="cline-any cline-yes">10x</span>
398
- <span class="cline-any cline-yes">10x</span>
399
- <span class="cline-any cline-yes">10x</span>
400
- <span class="cline-any cline-yes">10x</span>
401
- <span class="cline-any cline-yes">10x</span>
402
- <span class="cline-any cline-yes">10x</span>
403
- <span class="cline-any cline-yes">10x</span>
404
- <span class="cline-any cline-yes">10x</span>
405
- <span class="cline-any cline-yes">10x</span>
406
573
  <span class="cline-any cline-yes">1x</span>
407
- <span class="cline-any cline-yes">10x</span>
408
- <span class="cline-any cline-yes">2x</span>
409
- <span class="cline-any cline-yes">2x</span>
410
- <span class="cline-any cline-yes">7x</span>
411
- <span class="cline-any cline-yes">7x</span>
412
- <span class="cline-any cline-yes">7x</span>
413
- <span class="cline-any cline-yes">7x</span>
414
- <span class="cline-any cline-yes">7x</span>
415
- <span class="cline-any cline-yes">7x</span>
416
- <span class="cline-any cline-yes">7x</span>
417
- <span class="cline-any cline-yes">7x</span>
418
- <span class="cline-any cline-yes">7x</span>
419
- <span class="cline-any cline-yes">7x</span>
420
- <span class="cline-any cline-yes">7x</span>
421
- <span class="cline-any cline-yes">2x</span>
422
- <span class="cline-any cline-yes">2x</span>
423
- <span class="cline-any cline-yes">2x</span>
424
- <span class="cline-any cline-yes">2x</span>
574
+ <span class="cline-any cline-yes">1x</span>
575
+ <span class="cline-any cline-no">&nbsp;</span>
576
+ <span class="cline-any cline-no">&nbsp;</span>
577
+ <span class="cline-any cline-no">&nbsp;</span>
578
+ <span class="cline-any cline-no">&nbsp;</span>
579
+ <span class="cline-any cline-no">&nbsp;</span>
580
+ <span class="cline-any cline-no">&nbsp;</span>
581
+ <span class="cline-any cline-no">&nbsp;</span>
582
+ <span class="cline-any cline-yes">1x</span>
583
+ <span class="cline-any cline-yes">1x</span>
584
+ <span class="cline-any cline-yes">1x</span>
585
+ <span class="cline-any cline-no">&nbsp;</span>
586
+ <span class="cline-any cline-no">&nbsp;</span>
587
+ <span class="cline-any cline-no">&nbsp;</span>
588
+ <span class="cline-any cline-no">&nbsp;</span>
589
+ <span class="cline-any cline-no">&nbsp;</span>
590
+ <span class="cline-any cline-no">&nbsp;</span>
591
+ <span class="cline-any cline-no">&nbsp;</span>
592
+ <span class="cline-any cline-no">&nbsp;</span>
593
+ <span class="cline-any cline-no">&nbsp;</span>
425
594
  <span class="cline-any cline-no">&nbsp;</span>
426
595
  <span class="cline-any cline-no">&nbsp;</span>
427
596
  <span class="cline-any cline-no">&nbsp;</span>
@@ -437,21 +606,6 @@
437
606
  <span class="cline-any cline-no">&nbsp;</span>
438
607
  <span class="cline-any cline-no">&nbsp;</span>
439
608
  <span class="cline-any cline-no">&nbsp;</span>
440
- <span class="cline-any cline-yes">2x</span>
441
- <span class="cline-any cline-yes">2x</span>
442
- <span class="cline-any cline-yes">2x</span>
443
- <span class="cline-any cline-yes">2x</span>
444
- <span class="cline-any cline-yes">2x</span>
445
- <span class="cline-any cline-yes">2x</span>
446
- <span class="cline-any cline-yes">2x</span>
447
- <span class="cline-any cline-yes">2x</span>
448
- <span class="cline-any cline-yes">2x</span>
449
- <span class="cline-any cline-yes">2x</span>
450
- <span class="cline-any cline-yes">2x</span>
451
- <span class="cline-any cline-yes">2x</span>
452
- <span class="cline-any cline-yes">2x</span>
453
- <span class="cline-any cline-yes">2x</span>
454
- <span class="cline-any cline-yes">2x</span>
455
609
  <span class="cline-any cline-no">&nbsp;</span>
456
610
  <span class="cline-any cline-no">&nbsp;</span>
457
611
  <span class="cline-any cline-no">&nbsp;</span>
@@ -459,38 +613,94 @@
459
613
  <span class="cline-any cline-no">&nbsp;</span>
460
614
  <span class="cline-any cline-no">&nbsp;</span>
461
615
  <span class="cline-any cline-no">&nbsp;</span>
462
- <span class="cline-any cline-yes">2x</span>
463
- <span class="cline-any cline-yes">2x</span>
464
616
  <span class="cline-any cline-no">&nbsp;</span>
465
617
  <span class="cline-any cline-no">&nbsp;</span>
466
618
  <span class="cline-any cline-no">&nbsp;</span>
467
619
  <span class="cline-any cline-no">&nbsp;</span>
468
620
  <span class="cline-any cline-no">&nbsp;</span>
469
- <span class="cline-any cline-yes">2x</span>
470
- <span class="cline-any cline-yes">2x</span>
621
+ <span class="cline-any cline-no">&nbsp;</span>
622
+ <span class="cline-any cline-no">&nbsp;</span>
623
+ <span class="cline-any cline-no">&nbsp;</span>
624
+ <span class="cline-any cline-yes">1x</span>
625
+ <span class="cline-any cline-yes">1x</span>
626
+ <span class="cline-any cline-yes">1x</span>
627
+ <span class="cline-any cline-no">&nbsp;</span>
628
+ <span class="cline-any cline-no">&nbsp;</span>
629
+ <span class="cline-any cline-no">&nbsp;</span>
630
+ <span class="cline-any cline-no">&nbsp;</span>
631
+ <span class="cline-any cline-no">&nbsp;</span>
632
+ <span class="cline-any cline-no">&nbsp;</span>
633
+ <span class="cline-any cline-no">&nbsp;</span>
634
+ <span class="cline-any cline-no">&nbsp;</span>
635
+ <span class="cline-any cline-no">&nbsp;</span>
636
+ <span class="cline-any cline-no">&nbsp;</span>
637
+ <span class="cline-any cline-no">&nbsp;</span>
638
+ <span class="cline-any cline-no">&nbsp;</span>
639
+ <span class="cline-any cline-no">&nbsp;</span>
640
+ <span class="cline-any cline-no">&nbsp;</span>
471
641
  <span class="cline-any cline-no">&nbsp;</span>
472
642
  <span class="cline-any cline-no">&nbsp;</span>
473
643
  <span class="cline-any cline-no">&nbsp;</span>
474
644
  <span class="cline-any cline-no">&nbsp;</span>
645
+ <span class="cline-any cline-yes">1x</span>
646
+ <span class="cline-any cline-yes">1x</span>
647
+ <span class="cline-any cline-yes">1x</span>
475
648
  <span class="cline-any cline-no">&nbsp;</span>
476
649
  <span class="cline-any cline-no">&nbsp;</span>
650
+ <span class="cline-any cline-yes">1x</span>
651
+ <span class="cline-any cline-yes">1x</span>
652
+ <span class="cline-any cline-no">&nbsp;</span>
477
653
  <span class="cline-any cline-no">&nbsp;</span>
478
- <span class="cline-any cline-yes">2x</span>
479
- <span class="cline-any cline-yes">2x</span>
654
+ <span class="cline-any cline-yes">1x</span>
655
+ <span class="cline-any cline-yes">1x</span>
656
+ <span class="cline-any cline-yes">1x</span>
480
657
  <span class="cline-any cline-no">&nbsp;</span>
481
658
  <span class="cline-any cline-no">&nbsp;</span>
482
- <span class="cline-any cline-yes">2x</span>
483
- <span class="cline-any cline-yes">2x</span>
659
+ <span class="cline-any cline-yes">1x</span>
660
+ <span class="cline-any cline-yes">1x</span>
484
661
  <span class="cline-any cline-no">&nbsp;</span>
485
662
  <span class="cline-any cline-no">&nbsp;</span>
486
- <span class="cline-any cline-yes">2x</span>
487
- <span class="cline-any cline-yes">2x</span>
663
+ <span class="cline-any cline-yes">1x</span>
664
+ <span class="cline-any cline-yes">1x</span>
665
+ <span class="cline-any cline-yes">1x</span>
488
666
  <span class="cline-any cline-no">&nbsp;</span>
489
667
  <span class="cline-any cline-no">&nbsp;</span>
668
+ <span class="cline-any cline-yes">1x</span>
669
+ <span class="cline-any cline-yes">1x</span>
490
670
  <span class="cline-any cline-no">&nbsp;</span>
491
671
  <span class="cline-any cline-no">&nbsp;</span>
492
- <span class="cline-any cline-yes">2x</span>
493
- <span class="cline-any cline-yes">2x</span>
672
+ <span class="cline-any cline-yes">1x</span>
673
+ <span class="cline-any cline-yes">1x</span>
674
+ <span class="cline-any cline-no">&nbsp;</span>
675
+ <span class="cline-any cline-no">&nbsp;</span>
676
+ <span class="cline-any cline-no">&nbsp;</span>
677
+ <span class="cline-any cline-no">&nbsp;</span>
678
+ <span class="cline-any cline-yes">1x</span>
679
+ <span class="cline-any cline-yes">1x</span>
680
+ <span class="cline-any cline-no">&nbsp;</span>
681
+ <span class="cline-any cline-no">&nbsp;</span>
682
+ <span class="cline-any cline-no">&nbsp;</span>
683
+ <span class="cline-any cline-no">&nbsp;</span>
684
+ <span class="cline-any cline-yes">1x</span>
685
+ <span class="cline-any cline-yes">1x</span>
686
+ <span class="cline-any cline-no">&nbsp;</span>
687
+ <span class="cline-any cline-no">&nbsp;</span>
688
+ <span class="cline-any cline-yes">1x</span>
689
+ <span class="cline-any cline-yes">1x</span>
690
+ <span class="cline-any cline-no">&nbsp;</span>
691
+ <span class="cline-any cline-no">&nbsp;</span>
692
+ <span class="cline-any cline-yes">1x</span>
693
+ <span class="cline-any cline-yes">1x</span>
694
+ <span class="cline-any cline-no">&nbsp;</span>
695
+ <span class="cline-any cline-no">&nbsp;</span>
696
+ <span class="cline-any cline-yes">1x</span>
697
+ <span class="cline-any cline-yes">1x</span>
698
+ <span class="cline-any cline-no">&nbsp;</span>
699
+ <span class="cline-any cline-no">&nbsp;</span>
700
+ <span class="cline-any cline-no">&nbsp;</span>
701
+ <span class="cline-any cline-no">&nbsp;</span>
702
+ <span class="cline-any cline-yes">1x</span>
703
+ <span class="cline-any cline-yes">1x</span>
494
704
  <span class="cline-any cline-no">&nbsp;</span>
495
705
  <span class="cline-any cline-no">&nbsp;</span>
496
706
  <span class="cline-any cline-no">&nbsp;</span>
@@ -542,62 +752,62 @@ export <span class="fstat-no" title="function not covered" >function defineResou
542
752
  <span class="cstat-no" title="statement not covered" >}</span>
543
753
  &nbsp;
544
754
  // Hook computing default abilities for a given user
545
- export function defineUserAbilities (subject, can, cannot) {
546
- // Allow user registration
547
- can('service', 'users')
548
- can('create', 'users')
549
- // Verification email, reset password, etc.
550
- can('service', 'account')
551
- can(['create', 'verifyEmail'], 'account')
552
- // Allow import/export
553
- can('service', 'import-export')
554
- can('create', 'import-export')
555
- // Allow push registration
556
- can('service', 'push')
557
- can('create', 'push')
558
- if (subject &amp;&amp; subject._id) {
559
- // Read user profiles for authorizing
560
- can('read', 'users')
561
- // Update user profile and destroy it
562
- can(['update', 'remove'], 'users', { _id: subject._id })
563
- // Access authorisation service, then rights will be granted on a per-resource basis
564
- can('service', 'authorisations')
565
- // Access storage service, then rights will be granted on a per-resource basis
566
- can('service', 'storage')
567
- // This is for the user avatar
568
- // take care that the storage service uses 'id' as input but produces _id as output
569
- can('create', 'storage', { id: 'avatars/' + subject._id.toString() })
570
- can('create', 'storage', { id: 'avatars/' + subject._id.toString() + '.thumbnail' })
571
- can(['createMultipartUpload', 'completeMultipartUpload', 'uploadPart', 'putObject'], 'storage', { id: 'avatars/' + subject._id.toString() })
572
- can(['createMultipartUpload', 'completeMultipartUpload', 'uploadPart', 'putObject'], 'storage', { id: 'avatars/' + subject._id.toString() + '.thumbnail' })
573
- can('remove', 'storage', { _id: 'avatars/' + subject._id.toString() })
574
- can('remove', 'storage', { _id: 'avatars/' + subject._id.toString() + '.thumbnail' })
575
- // Avatar is part of user profiles so that they can be read by any
576
- can('read', 'storage', { _id: { $regex: '^avatars/*' } })
577
- }
578
- }
755
+ export <span class="fstat-no" title="function not covered" >function defineUserAbilities (subject, can, cannot) {</span>
756
+ <span class="cstat-no" title="statement not covered" > // Allow user registration</span>
757
+ <span class="cstat-no" title="statement not covered" > can('service', 'users')</span>
758
+ <span class="cstat-no" title="statement not covered" > can('create', 'users')</span>
759
+ <span class="cstat-no" title="statement not covered" > // Verification email, reset password, etc.</span>
760
+ <span class="cstat-no" title="statement not covered" > can('service', 'account')</span>
761
+ <span class="cstat-no" title="statement not covered" > can(['create', 'verifyEmail'], 'account')</span>
762
+ <span class="cstat-no" title="statement not covered" > // Allow import/export</span>
763
+ <span class="cstat-no" title="statement not covered" > can('service', 'import-export')</span>
764
+ <span class="cstat-no" title="statement not covered" > can('create', 'import-export')</span>
765
+ <span class="cstat-no" title="statement not covered" > // Allow push registration</span>
766
+ <span class="cstat-no" title="statement not covered" > can('service', 'push')</span>
767
+ <span class="cstat-no" title="statement not covered" > can('create', 'push')</span>
768
+ <span class="cstat-no" title="statement not covered" > if (subject &amp;&amp; subject._id) {</span>
769
+ <span class="cstat-no" title="statement not covered" > // Read user profiles for authorizing</span>
770
+ <span class="cstat-no" title="statement not covered" > can('read', 'users')</span>
771
+ <span class="cstat-no" title="statement not covered" > // Update user profile and destroy it</span>
772
+ <span class="cstat-no" title="statement not covered" > can(['update', 'remove'], 'users', { _id: subject._id })</span>
773
+ <span class="cstat-no" title="statement not covered" > // Access authorisation service, then rights will be granted on a per-resource basis</span>
774
+ <span class="cstat-no" title="statement not covered" > can('service', 'authorisations')</span>
775
+ <span class="cstat-no" title="statement not covered" > // Access storage service, then rights will be granted on a per-resource basis</span>
776
+ <span class="cstat-no" title="statement not covered" > can('service', 'storage')</span>
777
+ <span class="cstat-no" title="statement not covered" > // This is for the user avatar</span>
778
+ <span class="cstat-no" title="statement not covered" > // take care that the storage service uses 'id' as input but produces _id as output</span>
779
+ <span class="cstat-no" title="statement not covered" > can('create', 'storage', { id: 'avatars/' + subject._id.toString() })</span>
780
+ <span class="cstat-no" title="statement not covered" > can('create', 'storage', { id: 'avatars/' + subject._id.toString() + '.thumbnail' })</span>
781
+ <span class="cstat-no" title="statement not covered" > can(['createMultipartUpload', 'completeMultipartUpload', 'uploadPart', 'putObject'], 'storage', { id: 'avatars/' + subject._id.toString() })</span>
782
+ <span class="cstat-no" title="statement not covered" > can(['createMultipartUpload', 'completeMultipartUpload', 'uploadPart', 'putObject'], 'storage', { id: 'avatars/' + subject._id.toString() + '.thumbnail' })</span>
783
+ <span class="cstat-no" title="statement not covered" > can('remove', 'storage', { _id: 'avatars/' + subject._id.toString() })</span>
784
+ <span class="cstat-no" title="statement not covered" > can('remove', 'storage', { _id: 'avatars/' + subject._id.toString() + '.thumbnail' })</span>
785
+ <span class="cstat-no" title="statement not covered" > // Avatar is part of user profiles so that they can be read by any</span>
786
+ <span class="cstat-no" title="statement not covered" > can('read', 'storage', { _id: { $regex: '^avatars/*' } })</span>
787
+ <span class="cstat-no" title="statement not covered" > }</span>
788
+ <span class="cstat-no" title="statement not covered" >}</span>
579
789
  &nbsp;
580
790
  // Compute abilities for a given user
581
- export async function defineAbilities (subject, ...args) {
582
- const { build, can, cannot } = new AbilityBuilder(Ability)
583
- &nbsp;
584
- // Run registered hooks providing any additional arguments used to handle complex use cases
585
- await Promise.all(hooks.map(async hook =&gt; {
586
- await hook(subject, can, cannot, ...args)
587
- }))
588
- &nbsp;
589
- // CASL cannot infer the object type from the object itself so we need
590
- // to tell it how he can find the object type, i.e. service name.
591
- return build({
592
- detectSubjectType: resource =&gt; {
593
- if (!resource || typeof resource === 'string') <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
791
+ export <span class="fstat-no" title="function not covered" >async function defineAbilities (subject, ...args) {</span>
792
+ <span class="cstat-no" title="statement not covered" > const { build, can, cannot } = new AbilityBuilder(Ability)</span>
793
+ <span class="cstat-no" title="statement not covered" ></span>
794
+ <span class="cstat-no" title="statement not covered" > // Run registered hooks providing any additional arguments used to handle complex use cases</span>
795
+ <span class="cstat-no" title="statement not covered" > await Promise.all(hooks.map(async hook =&gt; {</span>
796
+ <span class="cstat-no" title="statement not covered" > await hook(subject, can, cannot, ...args)</span>
797
+ <span class="cstat-no" title="statement not covered" > }))</span>
798
+ <span class="cstat-no" title="statement not covered" ></span>
799
+ <span class="cstat-no" title="statement not covered" > // CASL cannot infer the object type from the object itself so we need</span>
800
+ <span class="cstat-no" title="statement not covered" > // to tell it how he can find the object type, i.e. service name.</span>
801
+ <span class="cstat-no" title="statement not covered" > return build({</span>
802
+ <span class="cstat-no" title="statement not covered" > detectSubjectType: resource =&gt; {</span>
803
+ <span class="cstat-no" title="statement not covered" > if (!resource || typeof resource === 'string') {</span>
594
804
  <span class="cstat-no" title="statement not covered" > return resource</span>
595
805
  <span class="cstat-no" title="statement not covered" > }</span>
596
- return resource[RESOURCE_TYPE_KEY]
597
- },
598
- resolveAction
599
- })
600
- }
806
+ <span class="cstat-no" title="statement not covered" > return resource[RESOURCE_TYPE_KEY]</span>
807
+ <span class="cstat-no" title="statement not covered" > },</span>
808
+ <span class="cstat-no" title="statement not covered" > resolveAction</span>
809
+ <span class="cstat-no" title="statement not covered" > })</span>
810
+ <span class="cstat-no" title="statement not covered" >}</span>
601
811
  &nbsp;
602
812
  defineAbilities.registerHook = function (hook) {
603
813
  if (!hooks.includes(hook)) {
@@ -609,35 +819,34 @@ defineAbilities.unregisterHook = <span class="fstat-no" title="function not cove
609
819
  <span class="cstat-no" title="statement not covered" > hooks = hooks.filter(registeredHook =&gt; registeredHook !== hook)</span>
610
820
  <span class="cstat-no" title="statement not covered" >}</span>
611
821
  &nbsp;
612
- export function hasServiceAbilities (abilities, service) {
613
- if (!abilities) <span class="branch-0 cbranch-no" title="branch not covered" >return false</span>
614
- // The unique identifier of a service is its path not its name.
615
- // Indeed we have for instance a 'groups' service in each context
616
- // Take care that in client we have the service path while on server we have the actual object
617
- const path = typeof service === 'string' <span class="branch-0 cbranch-no" title="branch not covered" >? service </span>: service.getPath()
618
- // */groups will allow to access any groups service in any context
619
- const allContextsPath = _.replace(path, /^.*\//, '*/')
620
- return abilities.can('service', path) ||
621
- abilities.can('service', `*/${path}`) ||
622
- abilities.can('service', allContextsPath)
623
- }
624
- &nbsp;
625
- export function hasResourceAbilities (abilities, operation, resourceType, context, resource) {
626
- if (!abilities) <span class="branch-0 cbranch-no" title="branch not covered" >return false</span>
627
- // Create a shallow copy adding context and type
628
- const object = Object.assign({}, resource)
629
- object[RESOURCE_TYPE_KEY] = resourceType
630
- // Add a virtual context to take it into account for object having no link to it
631
- if (context) <span class="branch-0 cbranch-no" title="branch not covered" >object.context = (typeof context === 'object' ? context._id.toString() : context.toString())</span>
632
- &nbsp;
633
- const result = abilities.can(operation, object)
822
+ export <span class="fstat-no" title="function not covered" >function hasServiceAbilities (abilities, service) {</span>
823
+ <span class="cstat-no" title="statement not covered" > if (!abilities) return false</span>
824
+ <span class="cstat-no" title="statement not covered" > // The unique identifier of a service is its path not its name.</span>
825
+ <span class="cstat-no" title="statement not covered" > // Indeed we have for instance a 'groups' service in each organisation</span>
826
+ <span class="cstat-no" title="statement not covered" > // Take care that in client we have the service path while on server we have the actual object</span>
827
+ <span class="cstat-no" title="statement not covered" > const path = typeof service === 'string' ? service : service.getPath()</span>
828
+ <span class="cstat-no" title="statement not covered" > // */groups will allow to access any groups service in any context</span>
829
+ <span class="cstat-no" title="statement not covered" > return abilities.can('service', path) ||</span>
830
+ <span class="cstat-no" title="statement not covered" > abilities.can('service', `*/${path}`) ||</span>
831
+ <span class="cstat-no" title="statement not covered" > abilities.can('service', _.replace(path, /^.*\//, '*/'))</span>
832
+ <span class="cstat-no" title="statement not covered" >}</span>
634
833
  &nbsp;
635
- return result
636
- }
834
+ export <span class="fstat-no" title="function not covered" >function hasResourceAbilities (abilities, operation, resourceType, context, resource) {</span>
835
+ <span class="cstat-no" title="statement not covered" > if (!abilities) return false</span>
836
+ <span class="cstat-no" title="statement not covered" > // Create a shallow copy adding context and type</span>
837
+ <span class="cstat-no" title="statement not covered" > const object = Object.assign({}, resource)</span>
838
+ <span class="cstat-no" title="statement not covered" > object[RESOURCE_TYPE_KEY] = resourceType</span>
839
+ <span class="cstat-no" title="statement not covered" > // Add a virtual context to take it into account for object having no link to it</span>
840
+ <span class="cstat-no" title="statement not covered" > if (context) object.context = (typeof context === 'object' ? context._id.toString() : context.toString())</span>
841
+ <span class="cstat-no" title="statement not covered" ></span>
842
+ <span class="cstat-no" title="statement not covered" > const result = abilities.can(operation, object)</span>
843
+ <span class="cstat-no" title="statement not covered" ></span>
844
+ <span class="cstat-no" title="statement not covered" > return result</span>
845
+ <span class="cstat-no" title="statement not covered" >}</span>
637
846
  &nbsp;
638
847
  // Utility function used to remove the virtual context from query
639
- export function removeContext (query) {
640
- _.forOwn(query, (value, key) =&gt; {
848
+ export <span class="fstat-no" title="function not covered" >function removeContext (query) {</span>
849
+ <span class="cstat-no" title="statement not covered" > _.forOwn(query, (value, key) =&gt; {</span>
641
850
  <span class="cstat-no" title="statement not covered" > // Process current attributes or recurse</span>
642
851
  <span class="cstat-no" title="statement not covered" > // Take care to nested fields like 'field._id'</span>
643
852
  <span class="cstat-no" title="statement not covered" > if (key === 'context') {</span>
@@ -653,20 +862,20 @@ export function removeContext (query) {
653
862
  <span class="cstat-no" title="statement not covered" > // Remove empty objects from query</span>
654
863
  <span class="cstat-no" title="statement not covered" > if (_.isEmpty(value)) delete query[key]</span>
655
864
  <span class="cstat-no" title="statement not covered" > }</span>
656
- })
657
- return query
658
- }
865
+ <span class="cstat-no" title="statement not covered" > })</span>
866
+ <span class="cstat-no" title="statement not covered" > return query</span>
867
+ <span class="cstat-no" title="statement not covered" >}</span>
659
868
  &nbsp;
660
869
  // Get the query used to filter the objects according to given abilities
661
870
  // A null query indicates that access should not be granted
662
- export function getQueryForAbilities (abilities, operation, resourceType) {
663
- if (!abilities) <span class="branch-0 cbranch-no" title="branch not covered" >return null</span>
664
- &nbsp;
665
- const query = toMongoQuery(abilities, resourceType, operation)
666
- // Remove any context to avoid taking it into account because it is not really stored on objects
667
- // We clone the object here because of references to the abilities rules (see https://github.com/kalisio/kdk/issues/384)
668
- return (query ? removeContext(_.cloneDeep(query)) <span class="branch-0 cbranch-no" title="branch not covered" >: null)</span>
669
- }
871
+ export <span class="fstat-no" title="function not covered" >function getQueryForAbilities (abilities, operation, resourceType) {</span>
872
+ <span class="cstat-no" title="statement not covered" > if (!abilities) return null</span>
873
+ <span class="cstat-no" title="statement not covered" ></span>
874
+ <span class="cstat-no" title="statement not covered" > const query = toMongoQuery(abilities, resourceType, operation)</span>
875
+ <span class="cstat-no" title="statement not covered" > // Remove any context to avoid taking it into account because it is not really stored on objects</span>
876
+ <span class="cstat-no" title="statement not covered" > // We clone the object here because of references to the abilities rules (see https://github.com/kalisio/kdk/issues/384)</span>
877
+ <span class="cstat-no" title="statement not covered" > return (query ? removeContext(_.cloneDeep(query)) : null)</span>
878
+ <span class="cstat-no" title="statement not covered" >}</span>
670
879
  &nbsp;
671
880
  <span class="cstat-no" title="statement not covered" ><span class="fstat-no" title="function not covered" >function buildSubjectsQueryForResource (resourceScope, resourceId, role) {</span></span>
672
881
  <span class="cstat-no" title="statement not covered" > const query = { [resourceScope]: { $elemMatch: { _id: resourceId } } }</span>
@@ -692,6 +901,112 @@ export <span class="fstat-no" title="function not covered" >function countSubjec
692
901
  <span class="cstat-no" title="statement not covered" > return subjectService.find({ query })</span>
693
902
  <span class="cstat-no" title="statement not covered" >}</span>
694
903
  &nbsp;
904
+ // Hook computing organisation abilities for a given user
905
+ export <span class="fstat-no" title="function not covered" >function defineOrganisationAbilities (subject, can, cannot) {</span>
906
+ <span class="cstat-no" title="statement not covered" > if (subject) {</span>
907
+ <span class="cstat-no" title="statement not covered" > // Create new organisations</span>
908
+ <span class="cstat-no" title="statement not covered" > can('service', 'organisations')</span>
909
+ <span class="cstat-no" title="statement not covered" > can('create', 'organisations')</span>
910
+ <span class="cstat-no" title="statement not covered" ></span>
911
+ <span class="cstat-no" title="statement not covered" > if (subject.organisations) {</span>
912
+ <span class="cstat-no" title="statement not covered" > subject.organisations.forEach(organisation =&gt; {</span>
913
+ <span class="cstat-no" title="statement not covered" > if (organisation._id) {</span>
914
+ <span class="cstat-no" title="statement not covered" > // Generic rules for resources</span>
915
+ <span class="cstat-no" title="statement not covered" > defineResourceRules(subject, organisation, 'organisations', can)</span>
916
+ <span class="cstat-no" title="statement not covered" > // Specific rules for organisations</span>
917
+ <span class="cstat-no" title="statement not covered" > const role = Roles[organisation.permissions]</span>
918
+ <span class="cstat-no" title="statement not covered" > if (role &gt;= Roles.member) {</span>
919
+ <span class="cstat-no" title="statement not covered" > // The unique identifier of a service is its path not its name.</span>
920
+ <span class="cstat-no" title="statement not covered" > // Indeed we have for instance a 'groups' service in each organisation.</span>
921
+ <span class="cstat-no" title="statement not covered" > can('service', organisation._id.toString() + '/members')</span>
922
+ <span class="cstat-no" title="statement not covered" > can('read', 'members', { context: organisation._id })</span>
923
+ <span class="cstat-no" title="statement not covered" > can('service', organisation._id.toString() + '/tags')</span>
924
+ <span class="cstat-no" title="statement not covered" > // Tags are public</span>
925
+ <span class="cstat-no" title="statement not covered" > can('read', 'tags', { context: organisation._id })</span>
926
+ <span class="cstat-no" title="statement not covered" > // Groups are private</span>
927
+ <span class="cstat-no" title="statement not covered" > can('service', organisation._id.toString() + '/groups')</span>
928
+ <span class="cstat-no" title="statement not covered" > can('service', organisation._id.toString() + '/storage')</span>
929
+ <span class="cstat-no" title="statement not covered" > can(['read', 'create', 'remove', 'createMultipartUpload', 'completeMultipartUpload', 'uploadPart', 'putObject'], 'storage', { context: organisation._id })</span>
930
+ <span class="cstat-no" title="statement not covered" > }</span>
931
+ <span class="cstat-no" title="statement not covered" > if (role &gt;= Roles.manager) {</span>
932
+ <span class="cstat-no" title="statement not covered" > can('update', 'members', { context: organisation._id })</span>
933
+ <span class="cstat-no" title="statement not covered" > // Managers can manage all groups/tags</span>
934
+ <span class="cstat-no" title="statement not covered" > can('all', 'groups', { context: organisation._id })</span>
935
+ <span class="cstat-no" title="statement not covered" > can(['create', 'remove'], 'authorisations', { resourcesService: organisation._id.toString() + '/groups', scope: 'groups' })</span>
936
+ <span class="cstat-no" title="statement not covered" > can('all', 'tags', { context: organisation._id })</span>
937
+ <span class="cstat-no" title="statement not covered" > // Remove invited members</span>
938
+ <span class="cstat-no" title="statement not covered" > can(['remove'], 'users', { 'sponsor.organisationId': organisation._id })</span>
939
+ <span class="cstat-no" title="statement not covered" > }</span>
940
+ <span class="cstat-no" title="statement not covered" > }</span>
941
+ <span class="cstat-no" title="statement not covered" > })</span>
942
+ <span class="cstat-no" title="statement not covered" > }</span>
943
+ <span class="cstat-no" title="statement not covered" > }</span>
944
+ <span class="cstat-no" title="statement not covered" >}</span>
945
+ &nbsp;
946
+ // Hook computing group abilities for a given user
947
+ export <span class="fstat-no" title="function not covered" >function defineGroupAbilities (subject, can, cannot) {</span>
948
+ <span class="cstat-no" title="statement not covered" > if (subject) {</span>
949
+ <span class="cstat-no" title="statement not covered" > if (subject.groups) {</span>
950
+ <span class="cstat-no" title="statement not covered" > subject.groups.forEach(group =&gt; {</span>
951
+ <span class="cstat-no" title="statement not covered" > if (group._id) {</span>
952
+ <span class="cstat-no" title="statement not covered" > // Specific rules for groups</span>
953
+ <span class="cstat-no" title="statement not covered" > const role = Roles[group.permissions]</span>
954
+ <span class="cstat-no" title="statement not covered" ></span>
955
+ <span class="cstat-no" title="statement not covered" > if (role &gt;= Roles.member) {</span>
956
+ <span class="cstat-no" title="statement not covered" > can('read', 'groups', { _id: group._id })</span>
957
+ <span class="cstat-no" title="statement not covered" > }</span>
958
+ <span class="cstat-no" title="statement not covered" > if (role &gt;= Roles.manager) {</span>
959
+ <span class="cstat-no" title="statement not covered" > can(['create', 'remove'], 'authorisations', { resource: group._id, permissions: 'member' })</span>
960
+ <span class="cstat-no" title="statement not covered" > }</span>
961
+ <span class="cstat-no" title="statement not covered" > }</span>
962
+ <span class="cstat-no" title="statement not covered" > })</span>
963
+ <span class="cstat-no" title="statement not covered" > }</span>
964
+ <span class="cstat-no" title="statement not covered" > }</span>
965
+ <span class="cstat-no" title="statement not covered" >}</span>
966
+ &nbsp;
967
+ // Helper functions to find the members of a given organisation
968
+ export <span class="fstat-no" title="function not covered" >function findMembersOfOrganisation (usersService, organisationId, role) {</span>
969
+ <span class="cstat-no" title="statement not covered" > return findSubjectsForResource(usersService, 'organisations', organisationId, role)</span>
970
+ <span class="cstat-no" title="statement not covered" >}</span>
971
+ &nbsp;
972
+ export <span class="fstat-no" title="function not covered" >function countMembersOfOrganisation (usersService, organisationId, role) {</span>
973
+ <span class="cstat-no" title="statement not covered" > return countSubjectsForResource(usersService, 'organisations', organisationId, role)</span>
974
+ <span class="cstat-no" title="statement not covered" >}</span>
975
+ &nbsp;
976
+ // Helper functions to find the members of a given group
977
+ export <span class="fstat-no" title="function not covered" >function findMembersOfGroup (membersService, groupId, role) {</span>
978
+ <span class="cstat-no" title="statement not covered" > return findSubjectsForResource(membersService, 'groups', groupId, role)</span>
979
+ <span class="cstat-no" title="statement not covered" >}</span>
980
+ &nbsp;
981
+ export <span class="fstat-no" title="function not covered" >function countMembersOfGroup (membersService, groupId, role) {</span>
982
+ <span class="cstat-no" title="statement not covered" > return countSubjectsForResource(membersService, 'groups', groupId, role)</span>
983
+ <span class="cstat-no" title="statement not covered" >}</span>
984
+ &nbsp;
985
+ // Helper functions to find the members with a given tag
986
+ export <span class="fstat-no" title="function not covered" >function findMembersWithTag (membersService, tagId) {</span>
987
+ <span class="cstat-no" title="statement not covered" > return findSubjectsForResource(membersService, 'tags', tagId)</span>
988
+ <span class="cstat-no" title="statement not covered" >}</span>
989
+ &nbsp;
990
+ export <span class="fstat-no" title="function not covered" >function countMembersWithTag (membersService, tagId) {</span>
991
+ <span class="cstat-no" title="statement not covered" > return countSubjectsForResource(membersService, 'tags', tagId)</span>
992
+ <span class="cstat-no" title="statement not covered" >}</span>
993
+ &nbsp;
994
+ export <span class="fstat-no" title="function not covered" >function getRoleForOrganisation (user, organisationId) {</span>
995
+ <span class="cstat-no" title="statement not covered" > const result = _.find(user.organisations, { _id: organisationId })</span>
996
+ <span class="cstat-no" title="statement not covered" > if (!_.isUndefined(result)) return result.permissions</span>
997
+ <span class="cstat-no" title="statement not covered" > return undefined</span>
998
+ <span class="cstat-no" title="statement not covered" >}</span>
999
+ &nbsp;
1000
+ export <span class="fstat-no" title="function not covered" >function getRoleForGroup (user, organisationId, groupId) {</span>
1001
+ <span class="cstat-no" title="statement not covered" > const result = _.find(user.groups, { context: organisationId, _id: groupId })</span>
1002
+ <span class="cstat-no" title="statement not covered" > if (!_.isUndefined(result)) return result.permissions</span>
1003
+ <span class="cstat-no" title="statement not covered" > return undefined</span>
1004
+ <span class="cstat-no" title="statement not covered" >}</span>
1005
+ &nbsp;
1006
+ export <span class="fstat-no" title="function not covered" >function findGroupsWithRole (user, organisationId, role) {</span>
1007
+ <span class="cstat-no" title="statement not covered" > return _.filter(user.groups || [], { context: organisationId, permissions: (typeof role === 'string' ? role : RoleNames[role]) })</span>
1008
+ <span class="cstat-no" title="statement not covered" >}</span>
1009
+ &nbsp;
695
1010
  export <span class="fstat-no" title="function not covered" >function isSeniorRole (roleName, juniorName) {</span>
696
1011
  <span class="cstat-no" title="statement not covered" > return Roles[roleName] &gt;= Roles[juniorName]</span>
697
1012
  <span class="cstat-no" title="statement not covered" >}</span>
@@ -718,7 +1033,7 @@ export <span class="fstat-no" title="function not covered" >function getJuniorRo
718
1033
  <div class='footer quiet pad2 space-top1 center small'>
719
1034
  Code coverage generated by
720
1035
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
721
- at 2025-07-24T10:00:20.476Z
1036
+ at 2024-08-13T10:02:04.843Z
722
1037
  </div>
723
1038
  <script src="../../prettify.js"></script>
724
1039
  <script>