@frictionless-ts/dataset 1.0.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 (242) hide show
  1. package/README.md +3 -0
  2. package/build/file/copy.d.ts +4 -0
  3. package/build/file/copy.js +7 -0
  4. package/build/file/copy.spec.d.ts +1 -0
  5. package/build/file/copy.spec.js +104 -0
  6. package/build/file/describe.d.ts +7 -0
  7. package/build/file/describe.js +9 -0
  8. package/build/file/fetch.d.ts +2 -0
  9. package/build/file/fetch.js +21 -0
  10. package/build/file/index.d.ts +9 -0
  11. package/build/file/index.js +10 -0
  12. package/build/file/infer.d.ts +10 -0
  13. package/build/file/infer.js +48 -0
  14. package/build/file/infer.spec.d.ts +1 -0
  15. package/build/file/infer.spec.js +141 -0
  16. package/build/file/load.d.ts +3 -0
  17. package/build/file/load.js +7 -0
  18. package/build/file/path.d.ts +2 -0
  19. package/build/file/path.js +17 -0
  20. package/build/file/save.d.ts +3 -0
  21. package/build/file/save.js +7 -0
  22. package/build/file/temp.d.ts +11 -0
  23. package/build/file/temp.js +23 -0
  24. package/build/file/validate.d.ts +6 -0
  25. package/build/file/validate.js +47 -0
  26. package/build/file/validate.spec.d.ts +1 -0
  27. package/build/file/validate.spec.js +180 -0
  28. package/build/folder/create.d.ts +1 -0
  29. package/build/folder/create.js +5 -0
  30. package/build/folder/index.d.ts +2 -0
  31. package/build/folder/index.js +3 -0
  32. package/build/folder/temp.d.ts +3 -0
  33. package/build/folder/temp.js +16 -0
  34. package/build/index.d.ts +36 -0
  35. package/build/index.js +35 -0
  36. package/build/package/index.d.ts +2 -0
  37. package/build/package/index.js +3 -0
  38. package/build/package/merge.d.ts +23 -0
  39. package/build/package/merge.js +12 -0
  40. package/build/package/path.d.ts +3 -0
  41. package/build/package/path.js +43 -0
  42. package/build/package/path.spec.d.ts +1 -0
  43. package/build/package/path.spec.js +56 -0
  44. package/build/plugin.d.ts +11 -0
  45. package/build/plugin.js +2 -0
  46. package/build/plugins/ckan/ckan/index.d.ts +1 -0
  47. package/build/plugins/ckan/ckan/index.js +2 -0
  48. package/build/plugins/ckan/ckan/request.d.ts +11 -0
  49. package/build/plugins/ckan/ckan/request.js +35 -0
  50. package/build/plugins/ckan/index.d.ts +4 -0
  51. package/build/plugins/ckan/index.js +5 -0
  52. package/build/plugins/ckan/package/Organization.d.ts +21 -0
  53. package/build/plugins/ckan/package/Organization.js +2 -0
  54. package/build/plugins/ckan/package/Package.d.ts +76 -0
  55. package/build/plugins/ckan/package/Package.js +2 -0
  56. package/build/plugins/ckan/package/Tag.d.ts +17 -0
  57. package/build/plugins/ckan/package/Tag.js +2 -0
  58. package/build/plugins/ckan/package/convert/fromCkan.d.ts +3 -0
  59. package/build/plugins/ckan/package/convert/fromCkan.js +63 -0
  60. package/build/plugins/ckan/package/convert/fromCkan.spec.d.ts +1 -0
  61. package/build/plugins/ckan/package/convert/fromCkan.spec.js +80 -0
  62. package/build/plugins/ckan/package/convert/toCkan.d.ts +22 -0
  63. package/build/plugins/ckan/package/convert/toCkan.js +51 -0
  64. package/build/plugins/ckan/package/convert/toCkan.spec.d.ts +1 -0
  65. package/build/plugins/ckan/package/convert/toCkan.spec.js +153 -0
  66. package/build/plugins/ckan/package/fixtures/ckan-package.json +308 -0
  67. package/build/plugins/ckan/package/index.d.ts +7 -0
  68. package/build/plugins/ckan/package/index.js +5 -0
  69. package/build/plugins/ckan/package/load.d.ts +21 -0
  70. package/build/plugins/ckan/package/load.js +74 -0
  71. package/build/plugins/ckan/package/load.spec.d.ts +1 -0
  72. package/build/plugins/ckan/package/load.spec.js +11 -0
  73. package/build/plugins/ckan/package/save.d.ts +10 -0
  74. package/build/plugins/ckan/package/save.js +83 -0
  75. package/build/plugins/ckan/package/save.spec.d.ts +1 -0
  76. package/build/plugins/ckan/package/save.spec.js +319 -0
  77. package/build/plugins/ckan/plugin.d.ts +19 -0
  78. package/build/plugins/ckan/plugin.js +18 -0
  79. package/build/plugins/ckan/plugin.spec.d.ts +1 -0
  80. package/build/plugins/ckan/plugin.spec.js +83 -0
  81. package/build/plugins/ckan/resource/Resource.d.ts +56 -0
  82. package/build/plugins/ckan/resource/Resource.js +2 -0
  83. package/build/plugins/ckan/resource/convert/fromCkan.d.ts +3 -0
  84. package/build/plugins/ckan/resource/convert/fromCkan.js +39 -0
  85. package/build/plugins/ckan/resource/convert/toCkan.d.ts +3 -0
  86. package/build/plugins/ckan/resource/convert/toCkan.js +20 -0
  87. package/build/plugins/ckan/resource/index.d.ts +3 -0
  88. package/build/plugins/ckan/resource/index.js +3 -0
  89. package/build/plugins/ckan/schema/Field.d.ts +34 -0
  90. package/build/plugins/ckan/schema/Field.js +2 -0
  91. package/build/plugins/ckan/schema/Schema.d.ts +10 -0
  92. package/build/plugins/ckan/schema/Schema.js +2 -0
  93. package/build/plugins/ckan/schema/convert/fixtures/ckan-schema.json +115 -0
  94. package/build/plugins/ckan/schema/convert/fromCkan.d.ts +3 -0
  95. package/build/plugins/ckan/schema/convert/fromCkan.js +47 -0
  96. package/build/plugins/ckan/schema/convert/fromCkan.spec.d.ts +1 -0
  97. package/build/plugins/ckan/schema/convert/fromCkan.spec.js +157 -0
  98. package/build/plugins/ckan/schema/convert/toCkan.d.ts +3 -0
  99. package/build/plugins/ckan/schema/convert/toCkan.js +50 -0
  100. package/build/plugins/ckan/schema/convert/toCkan.spec.d.ts +1 -0
  101. package/build/plugins/ckan/schema/convert/toCkan.spec.js +278 -0
  102. package/build/plugins/ckan/schema/index.d.ts +4 -0
  103. package/build/plugins/ckan/schema/index.js +3 -0
  104. package/build/plugins/datahub/index.d.ts +2 -0
  105. package/build/plugins/datahub/index.js +3 -0
  106. package/build/plugins/datahub/package/index.d.ts +1 -0
  107. package/build/plugins/datahub/package/index.js +2 -0
  108. package/build/plugins/datahub/package/load.d.ts +1 -0
  109. package/build/plugins/datahub/package/load.js +9 -0
  110. package/build/plugins/datahub/package/load.spec.d.ts +1 -0
  111. package/build/plugins/datahub/package/load.spec.js +11 -0
  112. package/build/plugins/datahub/plugin.d.ts +4 -0
  113. package/build/plugins/datahub/plugin.js +18 -0
  114. package/build/plugins/datahub/plugin.spec.d.ts +1 -0
  115. package/build/plugins/datahub/plugin.spec.js +78 -0
  116. package/build/plugins/descriptor/index.d.ts +1 -0
  117. package/build/plugins/descriptor/index.js +2 -0
  118. package/build/plugins/descriptor/plugin.d.ts +11 -0
  119. package/build/plugins/descriptor/plugin.js +29 -0
  120. package/build/plugins/descriptor/plugin.spec.d.ts +1 -0
  121. package/build/plugins/descriptor/plugin.spec.js +169 -0
  122. package/build/plugins/folder/index.d.ts +2 -0
  123. package/build/plugins/folder/index.js +3 -0
  124. package/build/plugins/folder/package/index.d.ts +2 -0
  125. package/build/plugins/folder/package/index.js +3 -0
  126. package/build/plugins/folder/package/load.d.ts +1 -0
  127. package/build/plugins/folder/package/load.js +6 -0
  128. package/build/plugins/folder/package/load.spec.d.ts +1 -0
  129. package/build/plugins/folder/package/load.spec.js +175 -0
  130. package/build/plugins/folder/package/save.d.ts +7 -0
  131. package/build/plugins/folder/package/save.js +35 -0
  132. package/build/plugins/folder/package/save.spec.d.ts +1 -0
  133. package/build/plugins/folder/package/save.spec.js +328 -0
  134. package/build/plugins/folder/plugin.d.ts +4 -0
  135. package/build/plugins/folder/plugin.js +19 -0
  136. package/build/plugins/folder/plugin.spec.d.ts +1 -0
  137. package/build/plugins/folder/plugin.spec.js +53 -0
  138. package/build/plugins/github/github/index.d.ts +1 -0
  139. package/build/plugins/github/github/index.js +2 -0
  140. package/build/plugins/github/github/path.d.ts +1 -0
  141. package/build/plugins/github/github/path.js +4 -0
  142. package/build/plugins/github/github/request.d.ts +15 -0
  143. package/build/plugins/github/github/request.js +43 -0
  144. package/build/plugins/github/index.d.ts +3 -0
  145. package/build/plugins/github/index.js +4 -0
  146. package/build/plugins/github/package/License.d.ts +21 -0
  147. package/build/plugins/github/package/License.js +2 -0
  148. package/build/plugins/github/package/Owner.d.ts +25 -0
  149. package/build/plugins/github/package/Owner.js +2 -0
  150. package/build/plugins/github/package/Package.d.ts +87 -0
  151. package/build/plugins/github/package/Package.js +2 -0
  152. package/build/plugins/github/package/convert/fromGithub.d.ts +3 -0
  153. package/build/plugins/github/package/convert/fromGithub.js +50 -0
  154. package/build/plugins/github/package/index.d.ts +6 -0
  155. package/build/plugins/github/package/index.js +4 -0
  156. package/build/plugins/github/package/load.d.ts +23 -0
  157. package/build/plugins/github/package/load.js +48 -0
  158. package/build/plugins/github/package/load.spec.d.ts +1 -0
  159. package/build/plugins/github/package/load.spec.js +15 -0
  160. package/build/plugins/github/package/save.d.ts +14 -0
  161. package/build/plugins/github/package/save.js +69 -0
  162. package/build/plugins/github/package/save.spec.d.ts +1 -0
  163. package/build/plugins/github/package/save.spec.js +566 -0
  164. package/build/plugins/github/plugin.d.ts +19 -0
  165. package/build/plugins/github/plugin.js +18 -0
  166. package/build/plugins/github/plugin.spec.d.ts +1 -0
  167. package/build/plugins/github/plugin.spec.js +73 -0
  168. package/build/plugins/github/resource/Resource.d.ts +29 -0
  169. package/build/plugins/github/resource/Resource.js +2 -0
  170. package/build/plugins/github/resource/convert/fromGithub.d.ts +5 -0
  171. package/build/plugins/github/resource/convert/fromGithub.js +24 -0
  172. package/build/plugins/github/resource/convert/toGithub.d.ts +3 -0
  173. package/build/plugins/github/resource/convert/toGithub.js +10 -0
  174. package/build/plugins/github/resource/index.d.ts +3 -0
  175. package/build/plugins/github/resource/index.js +3 -0
  176. package/build/plugins/zenodo/index.d.ts +3 -0
  177. package/build/plugins/zenodo/index.js +4 -0
  178. package/build/plugins/zenodo/package/Creator.d.ts +20 -0
  179. package/build/plugins/zenodo/package/Creator.js +2 -0
  180. package/build/plugins/zenodo/package/Package.d.ts +94 -0
  181. package/build/plugins/zenodo/package/Package.js +2 -0
  182. package/build/plugins/zenodo/package/convert/fromZenodo.d.ts +3 -0
  183. package/build/plugins/zenodo/package/convert/fromZenodo.js +43 -0
  184. package/build/plugins/zenodo/package/convert/toZenodo.d.ts +3 -0
  185. package/build/plugins/zenodo/package/convert/toZenodo.js +79 -0
  186. package/build/plugins/zenodo/package/index.d.ts +6 -0
  187. package/build/plugins/zenodo/package/index.js +5 -0
  188. package/build/plugins/zenodo/package/load.d.ts +23 -0
  189. package/build/plugins/zenodo/package/load.js +45 -0
  190. package/build/plugins/zenodo/package/load.spec.d.ts +1 -0
  191. package/build/plugins/zenodo/package/load.spec.js +15 -0
  192. package/build/plugins/zenodo/package/save.d.ts +13 -0
  193. package/build/plugins/zenodo/package/save.js +74 -0
  194. package/build/plugins/zenodo/package/save.spec.d.ts +1 -0
  195. package/build/plugins/zenodo/package/save.spec.js +524 -0
  196. package/build/plugins/zenodo/plugin.d.ts +19 -0
  197. package/build/plugins/zenodo/plugin.js +18 -0
  198. package/build/plugins/zenodo/plugin.spec.d.ts +1 -0
  199. package/build/plugins/zenodo/plugin.spec.js +78 -0
  200. package/build/plugins/zenodo/resource/Resource.d.ts +27 -0
  201. package/build/plugins/zenodo/resource/Resource.js +2 -0
  202. package/build/plugins/zenodo/resource/convert/fromZenodo.d.ts +10 -0
  203. package/build/plugins/zenodo/resource/convert/fromZenodo.js +18 -0
  204. package/build/plugins/zenodo/resource/convert/toZenodo.d.ts +3 -0
  205. package/build/plugins/zenodo/resource/convert/toZenodo.js +13 -0
  206. package/build/plugins/zenodo/resource/index.d.ts +3 -0
  207. package/build/plugins/zenodo/resource/index.js +3 -0
  208. package/build/plugins/zenodo/zenodo/index.d.ts +1 -0
  209. package/build/plugins/zenodo/zenodo/index.js +2 -0
  210. package/build/plugins/zenodo/zenodo/request.d.ts +12 -0
  211. package/build/plugins/zenodo/zenodo/request.js +36 -0
  212. package/build/plugins/zip/index.d.ts +2 -0
  213. package/build/plugins/zip/index.js +3 -0
  214. package/build/plugins/zip/package/index.d.ts +2 -0
  215. package/build/plugins/zip/package/index.js +3 -0
  216. package/build/plugins/zip/package/load.d.ts +1 -0
  217. package/build/plugins/zip/package/load.js +30 -0
  218. package/build/plugins/zip/package/load.spec.d.ts +1 -0
  219. package/build/plugins/zip/package/load.spec.js +173 -0
  220. package/build/plugins/zip/package/save.d.ts +5 -0
  221. package/build/plugins/zip/package/save.js +50 -0
  222. package/build/plugins/zip/package/save.spec.d.ts +1 -0
  223. package/build/plugins/zip/package/save.spec.js +287 -0
  224. package/build/plugins/zip/plugin.d.ts +11 -0
  225. package/build/plugins/zip/plugin.js +24 -0
  226. package/build/plugins/zip/plugin.spec.d.ts +1 -0
  227. package/build/plugins/zip/plugin.spec.js +158 -0
  228. package/build/resource/index.d.ts +1 -0
  229. package/build/resource/index.js +2 -0
  230. package/build/resource/save.d.ts +13 -0
  231. package/build/resource/save.js +53 -0
  232. package/build/resource/save.spec.d.ts +1 -0
  233. package/build/resource/save.spec.js +107 -0
  234. package/build/stream/concat.d.ts +3 -0
  235. package/build/stream/concat.js +5 -0
  236. package/build/stream/index.d.ts +3 -0
  237. package/build/stream/index.js +4 -0
  238. package/build/stream/load.d.ts +5 -0
  239. package/build/stream/load.js +46 -0
  240. package/build/stream/save.d.ts +5 -0
  241. package/build/stream/save.js +13 -0
  242. package/package.json +48 -0
@@ -0,0 +1,83 @@
1
+ import { blob } from "node:stream/consumers";
2
+ import { convertPackageToDescriptor, getFilename, getFormat, stringifyDescriptor, } from "@frictionless-ts/metadata";
3
+ import { getPackageBasepath } from "../../../package/index.js";
4
+ import { saveResourceFiles } from "../../../resource/index.js";
5
+ import { loadFileStream } from "../../../stream/index.js";
6
+ import { makeCkanApiRequest } from "../ckan/index.js";
7
+ import { convertResourceToCkan } from "../resource/index.js";
8
+ import { convertPackageToCkan } from "./convert/toCkan.js";
9
+ export async function savePackageToCkan(dataPackage, options) {
10
+ const { apiKey, ckanUrl, ownerOrg, datasetName } = options;
11
+ const basepath = getPackageBasepath(dataPackage);
12
+ const ckanPackage = convertPackageToCkan(dataPackage);
13
+ const payload = {
14
+ ...ckanPackage,
15
+ name: datasetName,
16
+ owner_org: ownerOrg,
17
+ resources: [],
18
+ };
19
+ const result = await makeCkanApiRequest({
20
+ action: "package_create",
21
+ payload,
22
+ ckanUrl: ckanUrl,
23
+ apiKey: apiKey,
24
+ });
25
+ const url = new URL(ckanUrl);
26
+ url.pathname = `/dataset/${result.name}`;
27
+ const resourceDescriptors = [];
28
+ for (const resource of dataPackage.resources) {
29
+ resourceDescriptors.push(await saveResourceFiles(resource, {
30
+ basepath,
31
+ withRemote: true,
32
+ withoutFolders: true,
33
+ saveFile: async (options) => {
34
+ const filename = getFilename(options.normalizedPath);
35
+ const ckanResource = convertResourceToCkan(resource);
36
+ const payload = {
37
+ ...ckanResource,
38
+ package_id: datasetName,
39
+ name: options.denormalizedPath,
40
+ format: getFormat(filename)?.toUpperCase(),
41
+ };
42
+ const upload = {
43
+ name: options.denormalizedPath,
44
+ data: await blob(await loadFileStream(options.normalizedPath)),
45
+ };
46
+ const result = await makeCkanApiRequest({
47
+ action: "resource_create",
48
+ payload,
49
+ upload,
50
+ ckanUrl,
51
+ apiKey,
52
+ });
53
+ return result.url;
54
+ },
55
+ }));
56
+ }
57
+ const descriptor = {
58
+ ...convertPackageToDescriptor(dataPackage, { basepath }),
59
+ resources: resourceDescriptors,
60
+ };
61
+ for (const denormalizedPath of ["datapackage.json"]) {
62
+ const payload = {
63
+ package_id: datasetName,
64
+ name: denormalizedPath,
65
+ };
66
+ const upload = {
67
+ name: denormalizedPath,
68
+ data: new Blob([stringifyDescriptor(descriptor)]),
69
+ };
70
+ await makeCkanApiRequest({
71
+ action: "resource_create",
72
+ payload,
73
+ upload,
74
+ ckanUrl,
75
+ apiKey,
76
+ });
77
+ }
78
+ return {
79
+ path: result.url,
80
+ datasetUrl: url.toString(),
81
+ };
82
+ }
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2F2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3BsdWdpbnMvY2thbi9wYWNrYWdlL3NhdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLHVCQUF1QixDQUFBO0FBRTVDLE9BQU8sRUFDTCwwQkFBMEIsRUFDMUIsV0FBVyxFQUNYLFNBQVMsRUFDVCxtQkFBbUIsR0FDcEIsTUFBTSwyQkFBMkIsQ0FBQTtBQUNsQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQTtBQUM5RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQTtBQUM5RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMEJBQTBCLENBQUE7QUFDekQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFFckQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDNUQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFFMUQsTUFBTSxDQUFDLEtBQUssVUFBVSxpQkFBaUIsQ0FDckMsV0FBb0IsRUFDcEIsT0FLQztJQUVELE1BQU0sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsR0FBRyxPQUFPLENBQUE7SUFFMUQsTUFBTSxRQUFRLEdBQUcsa0JBQWtCLENBQUMsV0FBVyxDQUFDLENBQUE7SUFDaEQsTUFBTSxXQUFXLEdBQUcsb0JBQW9CLENBQUMsV0FBVyxDQUFDLENBQUE7SUFFckQsTUFBTSxPQUFPLEdBQUc7UUFDZCxHQUFHLFdBQVc7UUFDZCxJQUFJLEVBQUUsV0FBVztRQUNqQixTQUFTLEVBQUUsUUFBUTtRQUNuQixTQUFTLEVBQUUsRUFBRTtLQUNkLENBQUE7SUFFRCxNQUFNLE1BQU0sR0FBRyxNQUFNLGtCQUFrQixDQUFDO1FBQ3RDLE1BQU0sRUFBRSxnQkFBZ0I7UUFDeEIsT0FBTztRQUNQLE9BQU8sRUFBRSxPQUFPO1FBQ2hCLE1BQU0sRUFBRSxNQUFNO0tBQ2YsQ0FBQyxDQUFBO0lBRUYsTUFBTSxHQUFHLEdBQUcsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDNUIsR0FBRyxDQUFDLFFBQVEsR0FBRyxZQUFZLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQTtJQUV4QyxNQUFNLG1CQUFtQixHQUFpQixFQUFFLENBQUE7SUFDNUMsS0FBSyxNQUFNLFFBQVEsSUFBSSxXQUFXLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDN0MsbUJBQW1CLENBQUMsSUFBSSxDQUN0QixNQUFNLGlCQUFpQixDQUFDLFFBQVEsRUFBRTtZQUNoQyxRQUFRO1lBQ1IsVUFBVSxFQUFFLElBQUk7WUFDaEIsY0FBYyxFQUFFLElBQUk7WUFDcEIsUUFBUSxFQUFFLEtBQUssRUFBQyxPQUFPLEVBQUMsRUFBRTtnQkFDeEIsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQTtnQkFDcEQsTUFBTSxZQUFZLEdBQUcscUJBQXFCLENBQUMsUUFBUSxDQUFDLENBQUE7Z0JBRXBELE1BQU0sT0FBTyxHQUFHO29CQUNkLEdBQUcsWUFBWTtvQkFDZixVQUFVLEVBQUUsV0FBVztvQkFDdkIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxnQkFBZ0I7b0JBQzlCLE1BQU0sRUFBRSxTQUFTLENBQUMsUUFBUSxDQUFDLEVBQUUsV0FBVyxFQUFFO2lCQUMzQyxDQUFBO2dCQUVELE1BQU0sTUFBTSxHQUFHO29CQUNiLElBQUksRUFBRSxPQUFPLENBQUMsZ0JBQWdCO29CQUM5QixJQUFJLEVBQUUsTUFBTSxJQUFJLENBQUMsTUFBTSxjQUFjLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDO2lCQUMvRCxDQUFBO2dCQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sa0JBQWtCLENBQWU7b0JBQ3BELE1BQU0sRUFBRSxpQkFBaUI7b0JBQ3pCLE9BQU87b0JBQ1AsTUFBTTtvQkFDTixPQUFPO29CQUNQLE1BQU07aUJBQ1AsQ0FBQyxDQUFBO2dCQUVGLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQTtZQUNuQixDQUFDO1NBQ0YsQ0FBQyxDQUNILENBQUE7SUFDSCxDQUFDO0lBRUQsTUFBTSxVQUFVLEdBQUc7UUFDakIsR0FBRywwQkFBMEIsQ0FBQyxXQUFXLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQztRQUN4RCxTQUFTLEVBQUUsbUJBQW1CO0tBQy9CLENBQUE7SUFFRCxLQUFLLE1BQU0sZ0JBQWdCLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLENBQUM7UUFDcEQsTUFBTSxPQUFPLEdBQUc7WUFDZCxVQUFVLEVBQUUsV0FBVztZQUN2QixJQUFJLEVBQUUsZ0JBQWdCO1NBQ3ZCLENBQUE7UUFFRCxNQUFNLE1BQU0sR0FBRztZQUNiLElBQUksRUFBRSxnQkFBZ0I7WUFDdEIsSUFBSSxFQUFFLElBQUksSUFBSSxDQUFDLENBQUMsbUJBQW1CLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztTQUNsRCxDQUFBO1FBRUQsTUFBTSxrQkFBa0IsQ0FBQztZQUN2QixNQUFNLEVBQUUsaUJBQWlCO1lBQ3pCLE9BQU87WUFDUCxNQUFNO1lBQ04sT0FBTztZQUNQLE1BQU07U0FDUCxDQUFDLENBQUE7SUFDSixDQUFDO0lBRUQsT0FBTztRQUNMLElBQUksRUFBRSxNQUFNLENBQUMsR0FBRztRQUNoQixVQUFVLEVBQUUsR0FBRyxDQUFDLFFBQVEsRUFBRTtLQUMzQixDQUFBO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGJsb2IgfSBmcm9tIFwibm9kZTpzdHJlYW0vY29uc3VtZXJzXCJcbmltcG9ydCB0eXBlIHsgRGVzY3JpcHRvciwgUGFja2FnZSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7XG4gIGNvbnZlcnRQYWNrYWdlVG9EZXNjcmlwdG9yLFxuICBnZXRGaWxlbmFtZSxcbiAgZ2V0Rm9ybWF0LFxuICBzdHJpbmdpZnlEZXNjcmlwdG9yLFxufSBmcm9tIFwiQGZyaWN0aW9ubGVzcy10cy9tZXRhZGF0YVwiXG5pbXBvcnQgeyBnZXRQYWNrYWdlQmFzZXBhdGggfSBmcm9tIFwiLi4vLi4vLi4vcGFja2FnZS9pbmRleC50c1wiXG5pbXBvcnQgeyBzYXZlUmVzb3VyY2VGaWxlcyB9IGZyb20gXCIuLi8uLi8uLi9yZXNvdXJjZS9pbmRleC50c1wiXG5pbXBvcnQgeyBsb2FkRmlsZVN0cmVhbSB9IGZyb20gXCIuLi8uLi8uLi9zdHJlYW0vaW5kZXgudHNcIlxuaW1wb3J0IHsgbWFrZUNrYW5BcGlSZXF1ZXN0IH0gZnJvbSBcIi4uL2NrYW4vaW5kZXgudHNcIlxuaW1wb3J0IHR5cGUgeyBDa2FuUmVzb3VyY2UgfSBmcm9tIFwiLi4vcmVzb3VyY2UvaW5kZXgudHNcIlxuaW1wb3J0IHsgY29udmVydFJlc291cmNlVG9Da2FuIH0gZnJvbSBcIi4uL3Jlc291cmNlL2luZGV4LnRzXCJcbmltcG9ydCB7IGNvbnZlcnRQYWNrYWdlVG9Da2FuIH0gZnJvbSBcIi4vY29udmVydC90b0NrYW4udHNcIlxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2F2ZVBhY2thZ2VUb0NrYW4oXG4gIGRhdGFQYWNrYWdlOiBQYWNrYWdlLFxuICBvcHRpb25zOiB7XG4gICAgYXBpS2V5OiBzdHJpbmdcbiAgICBja2FuVXJsOiBzdHJpbmdcbiAgICBvd25lck9yZzogc3RyaW5nXG4gICAgZGF0YXNldE5hbWU6IHN0cmluZ1xuICB9LFxuKSB7XG4gIGNvbnN0IHsgYXBpS2V5LCBja2FuVXJsLCBvd25lck9yZywgZGF0YXNldE5hbWUgfSA9IG9wdGlvbnNcblxuICBjb25zdCBiYXNlcGF0aCA9IGdldFBhY2thZ2VCYXNlcGF0aChkYXRhUGFja2FnZSlcbiAgY29uc3QgY2thblBhY2thZ2UgPSBjb252ZXJ0UGFja2FnZVRvQ2thbihkYXRhUGFja2FnZSlcblxuICBjb25zdCBwYXlsb2FkID0ge1xuICAgIC4uLmNrYW5QYWNrYWdlLFxuICAgIG5hbWU6IGRhdGFzZXROYW1lLFxuICAgIG93bmVyX29yZzogb3duZXJPcmcsXG4gICAgcmVzb3VyY2VzOiBbXSxcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdCA9IGF3YWl0IG1ha2VDa2FuQXBpUmVxdWVzdCh7XG4gICAgYWN0aW9uOiBcInBhY2thZ2VfY3JlYXRlXCIsXG4gICAgcGF5bG9hZCxcbiAgICBja2FuVXJsOiBja2FuVXJsLFxuICAgIGFwaUtleTogYXBpS2V5LFxuICB9KVxuXG4gIGNvbnN0IHVybCA9IG5ldyBVUkwoY2thblVybClcbiAgdXJsLnBhdGhuYW1lID0gYC9kYXRhc2V0LyR7cmVzdWx0Lm5hbWV9YFxuXG4gIGNvbnN0IHJlc291cmNlRGVzY3JpcHRvcnM6IERlc2NyaXB0b3JbXSA9IFtdXG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgZGF0YVBhY2thZ2UucmVzb3VyY2VzKSB7XG4gICAgcmVzb3VyY2VEZXNjcmlwdG9ycy5wdXNoKFxuICAgICAgYXdhaXQgc2F2ZVJlc291cmNlRmlsZXMocmVzb3VyY2UsIHtcbiAgICAgICAgYmFzZXBhdGgsXG4gICAgICAgIHdpdGhSZW1vdGU6IHRydWUsXG4gICAgICAgIHdpdGhvdXRGb2xkZXJzOiB0cnVlLFxuICAgICAgICBzYXZlRmlsZTogYXN5bmMgb3B0aW9ucyA9PiB7XG4gICAgICAgICAgY29uc3QgZmlsZW5hbWUgPSBnZXRGaWxlbmFtZShvcHRpb25zLm5vcm1hbGl6ZWRQYXRoKVxuICAgICAgICAgIGNvbnN0IGNrYW5SZXNvdXJjZSA9IGNvbnZlcnRSZXNvdXJjZVRvQ2thbihyZXNvdXJjZSlcblxuICAgICAgICAgIGNvbnN0IHBheWxvYWQgPSB7XG4gICAgICAgICAgICAuLi5ja2FuUmVzb3VyY2UsXG4gICAgICAgICAgICBwYWNrYWdlX2lkOiBkYXRhc2V0TmFtZSxcbiAgICAgICAgICAgIG5hbWU6IG9wdGlvbnMuZGVub3JtYWxpemVkUGF0aCxcbiAgICAgICAgICAgIGZvcm1hdDogZ2V0Rm9ybWF0KGZpbGVuYW1lKT8udG9VcHBlckNhc2UoKSxcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCB1cGxvYWQgPSB7XG4gICAgICAgICAgICBuYW1lOiBvcHRpb25zLmRlbm9ybWFsaXplZFBhdGgsXG4gICAgICAgICAgICBkYXRhOiBhd2FpdCBibG9iKGF3YWl0IGxvYWRGaWxlU3RyZWFtKG9wdGlvbnMubm9ybWFsaXplZFBhdGgpKSxcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBtYWtlQ2thbkFwaVJlcXVlc3Q8Q2thblJlc291cmNlPih7XG4gICAgICAgICAgICBhY3Rpb246IFwicmVzb3VyY2VfY3JlYXRlXCIsXG4gICAgICAgICAgICBwYXlsb2FkLFxuICAgICAgICAgICAgdXBsb2FkLFxuICAgICAgICAgICAgY2thblVybCxcbiAgICAgICAgICAgIGFwaUtleSxcbiAgICAgICAgICB9KVxuXG4gICAgICAgICAgcmV0dXJuIHJlc3VsdC51cmxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgIClcbiAgfVxuXG4gIGNvbnN0IGRlc2NyaXB0b3IgPSB7XG4gICAgLi4uY29udmVydFBhY2thZ2VUb0Rlc2NyaXB0b3IoZGF0YVBhY2thZ2UsIHsgYmFzZXBhdGggfSksXG4gICAgcmVzb3VyY2VzOiByZXNvdXJjZURlc2NyaXB0b3JzLFxuICB9XG5cbiAgZm9yIChjb25zdCBkZW5vcm1hbGl6ZWRQYXRoIG9mIFtcImRhdGFwYWNrYWdlLmpzb25cIl0pIHtcbiAgICBjb25zdCBwYXlsb2FkID0ge1xuICAgICAgcGFja2FnZV9pZDogZGF0YXNldE5hbWUsXG4gICAgICBuYW1lOiBkZW5vcm1hbGl6ZWRQYXRoLFxuICAgIH1cblxuICAgIGNvbnN0IHVwbG9hZCA9IHtcbiAgICAgIG5hbWU6IGRlbm9ybWFsaXplZFBhdGgsXG4gICAgICBkYXRhOiBuZXcgQmxvYihbc3RyaW5naWZ5RGVzY3JpcHRvcihkZXNjcmlwdG9yKV0pLFxuICAgIH1cblxuICAgIGF3YWl0IG1ha2VDa2FuQXBpUmVxdWVzdCh7XG4gICAgICBhY3Rpb246IFwicmVzb3VyY2VfY3JlYXRlXCIsXG4gICAgICBwYXlsb2FkLFxuICAgICAgdXBsb2FkLFxuICAgICAgY2thblVybCxcbiAgICAgIGFwaUtleSxcbiAgICB9KVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBwYXRoOiByZXN1bHQudXJsLFxuICAgIGRhdGFzZXRVcmw6IHVybC50b1N0cmluZygpLFxuICB9XG59XG4iXX0=
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,319 @@
1
+ import { relative } from "node:path";
2
+ import { loadPackageDescriptor } from "@frictionless-ts/metadata";
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { savePackageToCkan } from "./save.js";
5
+ describe("savePackageToCkan", () => {
6
+ const getFixturePath = (name) => relative(process.cwd(), `${import.meta.dirname}/fixtures/${name}`);
7
+ const mockPackage = {
8
+ name: "test-package",
9
+ title: "Test Package",
10
+ description: "A test package",
11
+ version: "1.0.0",
12
+ resources: [
13
+ {
14
+ name: "test-resource",
15
+ path: getFixturePath("data.csv"),
16
+ format: "csv",
17
+ bytes: 100,
18
+ },
19
+ ],
20
+ };
21
+ const mockOptions = {
22
+ apiKey: "test-api-key",
23
+ ckanUrl: "https://ckan.example.com",
24
+ ownerOrg: "test-org",
25
+ datasetName: "test-dataset",
26
+ };
27
+ const originalFetch = globalThis.fetch;
28
+ let fetchMock;
29
+ beforeEach(() => {
30
+ fetchMock = vi.fn();
31
+ // @ts-ignore
32
+ globalThis.fetch = fetchMock;
33
+ });
34
+ afterEach(() => {
35
+ globalThis.fetch = originalFetch;
36
+ vi.resetAllMocks();
37
+ });
38
+ it.skip("should save a package", async () => {
39
+ const dataPackage = await loadPackageDescriptor("core/package/fixtures/package.json");
40
+ const result = await savePackageToCkan(dataPackage, {
41
+ ckanUrl: "http://localhost:5000/",
42
+ apiKey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJ1T0Y0VUNybTU5Y0dzdlk3ejhreF9CeC02R0w4RDBOdW9QS0J0WkJFXzlJIiwiaWF0IjoxNzQ3OTI0NDg5fQ.ioGiLlZkm24xHQRBas5X5ig5eU7u_fIjkl4oifGnLaA",
43
+ datasetName: "test",
44
+ ownerOrg: "test",
45
+ });
46
+ expect(result).toBeDefined();
47
+ });
48
+ it("creates a package in CKAN with correct API calls", async () => {
49
+ fetchMock.mockResolvedValueOnce({
50
+ ok: true,
51
+ json: () => Promise.resolve({
52
+ success: true,
53
+ result: {
54
+ name: "test-dataset",
55
+ url: "https://ckan.example.com/dataset/test-dataset",
56
+ },
57
+ }),
58
+ });
59
+ fetchMock.mockResolvedValueOnce({
60
+ ok: true,
61
+ json: () => Promise.resolve({
62
+ success: true,
63
+ result: {
64
+ id: "resource-1",
65
+ url: "https://ckan.example.com/dataset/test-dataset/resource/resource-1",
66
+ },
67
+ }),
68
+ });
69
+ fetchMock.mockResolvedValueOnce({
70
+ ok: true,
71
+ json: () => Promise.resolve({
72
+ success: true,
73
+ result: {
74
+ id: "resource-2",
75
+ url: "https://ckan.example.com/dataset/test-dataset/resource/resource-2",
76
+ },
77
+ }),
78
+ });
79
+ const result = await savePackageToCkan(mockPackage, mockOptions);
80
+ expect(fetchMock).toHaveBeenCalledTimes(3);
81
+ const packageCreateCall = fetchMock.mock.calls[0];
82
+ expect(packageCreateCall).toBeDefined();
83
+ if (!packageCreateCall)
84
+ return;
85
+ expect(packageCreateCall[0]).toEqual("https://ckan.example.com/api/3/action/package_create");
86
+ expect(packageCreateCall[1]).toMatchObject({
87
+ method: "POST",
88
+ headers: {
89
+ Authorization: "test-api-key",
90
+ "Content-Type": "application/json",
91
+ },
92
+ });
93
+ const packagePayload = JSON.parse(packageCreateCall[1].body);
94
+ expect(packagePayload.name).toEqual("test-dataset");
95
+ expect(packagePayload.owner_org).toEqual("test-org");
96
+ expect(packagePayload.title).toEqual("Test Package");
97
+ expect(packagePayload.notes).toEqual("A test package");
98
+ expect(packagePayload.resources).toEqual([]);
99
+ expect(result).toEqual({
100
+ path: "https://ckan.example.com/dataset/test-dataset",
101
+ datasetUrl: "https://ckan.example.com/dataset/test-dataset",
102
+ });
103
+ });
104
+ it("creates resources with file uploads", async () => {
105
+ fetchMock.mockResolvedValueOnce({
106
+ ok: true,
107
+ json: () => Promise.resolve({
108
+ success: true,
109
+ result: {
110
+ name: "test-dataset",
111
+ url: "https://ckan.example.com/dataset/test-dataset",
112
+ },
113
+ }),
114
+ });
115
+ fetchMock.mockResolvedValueOnce({
116
+ ok: true,
117
+ json: () => Promise.resolve({
118
+ success: true,
119
+ result: {
120
+ id: "resource-1",
121
+ url: "https://ckan.example.com/dataset/test-dataset/resource/resource-1",
122
+ },
123
+ }),
124
+ });
125
+ fetchMock.mockResolvedValueOnce({
126
+ ok: true,
127
+ json: () => Promise.resolve({
128
+ success: true,
129
+ result: {
130
+ id: "resource-2",
131
+ url: "https://ckan.example.com/dataset/test-dataset/resource/resource-2",
132
+ },
133
+ }),
134
+ });
135
+ await savePackageToCkan(mockPackage, mockOptions);
136
+ const resourceCreateCall = fetchMock.mock.calls[1];
137
+ expect(resourceCreateCall).toBeDefined();
138
+ if (!resourceCreateCall)
139
+ return;
140
+ expect(resourceCreateCall[0]).toEqual("https://ckan.example.com/api/3/action/resource_create");
141
+ expect(resourceCreateCall[1]).toMatchObject({
142
+ method: "POST",
143
+ headers: {
144
+ Authorization: "test-api-key",
145
+ },
146
+ });
147
+ const formData = resourceCreateCall[1].body;
148
+ expect(formData).toBeInstanceOf(FormData);
149
+ expect(formData.get("package_id")).toEqual("test-dataset");
150
+ expect(formData.get("name")).toEqual("data.csv");
151
+ });
152
+ it("creates datapackage.json resource", async () => {
153
+ fetchMock.mockResolvedValueOnce({
154
+ ok: true,
155
+ json: () => Promise.resolve({
156
+ success: true,
157
+ result: {
158
+ name: "test-dataset",
159
+ url: "https://ckan.example.com/dataset/test-dataset",
160
+ },
161
+ }),
162
+ });
163
+ fetchMock.mockResolvedValueOnce({
164
+ ok: true,
165
+ json: () => Promise.resolve({
166
+ success: true,
167
+ result: {
168
+ id: "resource-1",
169
+ url: "https://ckan.example.com/dataset/test-dataset/resource/resource-1",
170
+ },
171
+ }),
172
+ });
173
+ fetchMock.mockResolvedValueOnce({
174
+ ok: true,
175
+ json: () => Promise.resolve({
176
+ success: true,
177
+ result: {
178
+ id: "resource-2",
179
+ url: "https://ckan.example.com/dataset/test-dataset/resource/resource-2",
180
+ },
181
+ }),
182
+ });
183
+ await savePackageToCkan(mockPackage, mockOptions);
184
+ const datapackageCreateCall = fetchMock.mock.calls[2];
185
+ expect(datapackageCreateCall).toBeDefined();
186
+ if (!datapackageCreateCall)
187
+ return;
188
+ expect(datapackageCreateCall[0]).toEqual("https://ckan.example.com/api/3/action/resource_create");
189
+ const formData = datapackageCreateCall[1].body;
190
+ expect(formData).toBeInstanceOf(FormData);
191
+ expect(formData.get("package_id")).toEqual("test-dataset");
192
+ expect(formData.get("name")).toEqual("datapackage.json");
193
+ const uploadBlob = formData.get("upload");
194
+ expect(uploadBlob).toBeInstanceOf(Blob);
195
+ });
196
+ it("handles API errors from package_create", async () => {
197
+ fetchMock.mockResolvedValueOnce({
198
+ ok: false,
199
+ status: 400,
200
+ statusText: "Bad Request",
201
+ text: () => Promise.resolve("Invalid package data"),
202
+ });
203
+ await expect(savePackageToCkan(mockPackage, mockOptions)).rejects.toThrow("CKAN API error: 400 Bad Request");
204
+ });
205
+ it("handles API errors from resource_create", async () => {
206
+ fetchMock.mockResolvedValueOnce({
207
+ ok: true,
208
+ json: () => Promise.resolve({
209
+ success: true,
210
+ result: {
211
+ name: "test-dataset",
212
+ url: "https://ckan.example.com/dataset/test-dataset",
213
+ },
214
+ }),
215
+ });
216
+ fetchMock.mockResolvedValueOnce({
217
+ ok: false,
218
+ status: 500,
219
+ statusText: "Internal Server Error",
220
+ text: () => Promise.resolve("Failed to create resource"),
221
+ });
222
+ await expect(savePackageToCkan(mockPackage, mockOptions)).rejects.toThrow("CKAN API error: 500 Internal Server Error");
223
+ });
224
+ it("handles CKAN API success: false responses", async () => {
225
+ fetchMock.mockResolvedValueOnce({
226
+ ok: true,
227
+ json: () => Promise.resolve({
228
+ success: false,
229
+ error: {
230
+ message: "Package already exists",
231
+ },
232
+ }),
233
+ });
234
+ await expect(savePackageToCkan(mockPackage, mockOptions)).rejects.toThrow("CKAN API error");
235
+ });
236
+ it("handles packages with multiple resources", async () => {
237
+ const multiResourcePackage = {
238
+ ...mockPackage,
239
+ resources: [
240
+ {
241
+ name: "resource-1",
242
+ path: getFixturePath("data.csv"),
243
+ format: "csv",
244
+ },
245
+ {
246
+ name: "resource-2",
247
+ path: getFixturePath("data.csv"),
248
+ format: "json",
249
+ },
250
+ ],
251
+ };
252
+ fetchMock.mockResolvedValue({
253
+ ok: true,
254
+ json: () => Promise.resolve({
255
+ success: true,
256
+ result: {
257
+ name: "test-dataset",
258
+ url: "https://ckan.example.com/dataset/test-dataset",
259
+ },
260
+ }),
261
+ });
262
+ await savePackageToCkan(multiResourcePackage, mockOptions);
263
+ expect(fetchMock).toHaveBeenCalledTimes(4);
264
+ const secondResourceCall = fetchMock.mock.calls[2];
265
+ expect(secondResourceCall).toBeDefined();
266
+ if (!secondResourceCall)
267
+ return;
268
+ expect(secondResourceCall[0]).toEqual("https://ckan.example.com/api/3/action/resource_create");
269
+ });
270
+ it("handles packages with no resources", async () => {
271
+ const emptyPackage = {
272
+ ...mockPackage,
273
+ resources: [],
274
+ };
275
+ fetchMock.mockResolvedValueOnce({
276
+ ok: true,
277
+ json: () => Promise.resolve({
278
+ success: true,
279
+ result: {
280
+ name: "test-dataset",
281
+ url: "https://ckan.example.com/dataset/test-dataset",
282
+ },
283
+ }),
284
+ });
285
+ fetchMock.mockResolvedValueOnce({
286
+ ok: true,
287
+ json: () => Promise.resolve({
288
+ success: true,
289
+ result: {
290
+ id: "resource-1",
291
+ url: "https://ckan.example.com/dataset/test-dataset/resource/resource-1",
292
+ },
293
+ }),
294
+ });
295
+ const result = await savePackageToCkan(emptyPackage, mockOptions);
296
+ expect(fetchMock).toHaveBeenCalledTimes(2);
297
+ expect(result.datasetUrl).toEqual("https://ckan.example.com/dataset/test-dataset");
298
+ });
299
+ it("passes API key in Authorization header", async () => {
300
+ fetchMock.mockResolvedValue({
301
+ ok: true,
302
+ json: () => Promise.resolve({
303
+ success: true,
304
+ result: { name: "test-dataset" },
305
+ }),
306
+ });
307
+ await savePackageToCkan(mockPackage, {
308
+ ...mockOptions,
309
+ apiKey: "custom-api-key",
310
+ });
311
+ const firstCall = fetchMock.mock.calls[0];
312
+ expect(firstCall).toBeDefined();
313
+ if (!firstCall)
314
+ return;
315
+ const headers = firstCall[1].headers;
316
+ expect(headers.Authorization).toEqual("custom-api-key");
317
+ });
318
+ });
319
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2F2ZS5zcGVjLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcGx1Z2lucy9ja2FuL3BhY2thZ2Uvc2F2ZS5zcGVjLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFFcEMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLE1BQU0sUUFBUSxDQUFBO0FBQ3hFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFdBQVcsQ0FBQTtBQUU3QyxRQUFRLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxFQUFFO0lBQ2pDLE1BQU0sY0FBYyxHQUFHLENBQUMsSUFBWSxFQUFFLEVBQUUsQ0FDdEMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxhQUFhLElBQUksRUFBRSxDQUFDLENBQUE7SUFFcEUsTUFBTSxXQUFXLEdBQVk7UUFDM0IsSUFBSSxFQUFFLGNBQWM7UUFDcEIsS0FBSyxFQUFFLGNBQWM7UUFDckIsV0FBVyxFQUFFLGdCQUFnQjtRQUM3QixPQUFPLEVBQUUsT0FBTztRQUNoQixTQUFTLEVBQUU7WUFDVDtnQkFDRSxJQUFJLEVBQUUsZUFBZTtnQkFDckIsSUFBSSxFQUFFLGNBQWMsQ0FBQyxVQUFVLENBQUM7Z0JBQ2hDLE1BQU0sRUFBRSxLQUFLO2dCQUNiLEtBQUssRUFBRSxHQUFHO2FBQ1g7U0FDRjtLQUNGLENBQUE7SUFFRCxNQUFNLFdBQVcsR0FBRztRQUNsQixNQUFNLEVBQUUsY0FBYztRQUN0QixPQUFPLEVBQUUsMEJBQTBCO1FBQ25DLFFBQVEsRUFBRSxVQUFVO1FBQ3BCLFdBQVcsRUFBRSxjQUFjO0tBQzVCLENBQUE7SUFFRCxNQUFNLGFBQWEsR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFBO0lBQ3RDLElBQUksU0FBbUMsQ0FBQTtJQUV2QyxVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2QsU0FBUyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQTtRQUNuQixhQUFhO1FBQ2IsVUFBVSxDQUFDLEtBQUssR0FBRyxTQUFTLENBQUE7SUFDOUIsQ0FBQyxDQUFDLENBQUE7SUFFRixTQUFTLENBQUMsR0FBRyxFQUFFO1FBQ2IsVUFBVSxDQUFDLEtBQUssR0FBRyxhQUFhLENBQUE7UUFDaEMsRUFBRSxDQUFDLGFBQWEsRUFBRSxDQUFBO0lBQ3BCLENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxLQUFLLElBQUksRUFBRTtRQUMxQyxNQUFNLFdBQVcsR0FBRyxNQUFNLHFCQUFxQixDQUM3QyxvQ0FBb0MsQ0FDckMsQ0FBQTtRQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0saUJBQWlCLENBQUMsV0FBVyxFQUFFO1lBQ2xELE9BQU8sRUFBRSx3QkFBd0I7WUFDakMsTUFBTSxFQUNKLGlMQUFpTDtZQUNuTCxXQUFXLEVBQUUsTUFBTTtZQUNuQixRQUFRLEVBQUUsTUFBTTtTQUNqQixDQUFDLENBQUE7UUFFRixNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUE7SUFDOUIsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsa0RBQWtELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDaEUsU0FBUyxDQUFDLHFCQUFxQixDQUFDO1lBQzlCLEVBQUUsRUFBRSxJQUFJO1lBQ1IsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUNULE9BQU8sQ0FBQyxPQUFPLENBQUM7Z0JBQ2QsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsTUFBTSxFQUFFO29CQUNOLElBQUksRUFBRSxjQUFjO29CQUNwQixHQUFHLEVBQUUsK0NBQStDO2lCQUNyRDthQUNGLENBQUM7U0FDTCxDQUFDLENBQUE7UUFFRixTQUFTLENBQUMscUJBQXFCLENBQUM7WUFDOUIsRUFBRSxFQUFFLElBQUk7WUFDUixJQUFJLEVBQUUsR0FBRyxFQUFFLENBQ1QsT0FBTyxDQUFDLE9BQU8sQ0FBQztnQkFDZCxPQUFPLEVBQUUsSUFBSTtnQkFDYixNQUFNLEVBQUU7b0JBQ04sRUFBRSxFQUFFLFlBQVk7b0JBQ2hCLEdBQUcsRUFBRSxtRUFBbUU7aUJBQ3pFO2FBQ0YsQ0FBQztTQUNMLENBQUMsQ0FBQTtRQUVGLFNBQVMsQ0FBQyxxQkFBcUIsQ0FBQztZQUM5QixFQUFFLEVBQUUsSUFBSTtZQUNSLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FDVCxPQUFPLENBQUMsT0FBTyxDQUFDO2dCQUNkLE9BQU8sRUFBRSxJQUFJO2dCQUNiLE1BQU0sRUFBRTtvQkFDTixFQUFFLEVBQUUsWUFBWTtvQkFDaEIsR0FBRyxFQUFFLG1FQUFtRTtpQkFDekU7YUFDRixDQUFDO1NBQ0wsQ0FBQyxDQUFBO1FBRUYsTUFBTSxNQUFNLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsV0FBVyxDQUFDLENBQUE7UUFFaEUsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxDQUFBO1FBRTFDLE1BQU0saUJBQWlCLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDakQsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsV0FBVyxFQUFFLENBQUE7UUFDdkMsSUFBSSxDQUFDLGlCQUFpQjtZQUFFLE9BQU07UUFFOUIsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUNsQyxzREFBc0QsQ0FDdkQsQ0FBQTtRQUNELE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQztZQUN6QyxNQUFNLEVBQUUsTUFBTTtZQUNkLE9BQU8sRUFBRTtnQkFDUCxhQUFhLEVBQUUsY0FBYztnQkFDN0IsY0FBYyxFQUFFLGtCQUFrQjthQUNuQztTQUNGLENBQUMsQ0FBQTtRQUVGLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDNUQsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUE7UUFDbkQsTUFBTSxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUE7UUFDcEQsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUE7UUFDcEQsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtRQUN0RCxNQUFNLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUU1QyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDO1lBQ3JCLElBQUksRUFBRSwrQ0FBK0M7WUFDckQsVUFBVSxFQUFFLCtDQUErQztTQUM1RCxDQUFDLENBQUE7SUFDSixDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyxxQ0FBcUMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNuRCxTQUFTLENBQUMscUJBQXFCLENBQUM7WUFDOUIsRUFBRSxFQUFFLElBQUk7WUFDUixJQUFJLEVBQUUsR0FBRyxFQUFFLENBQ1QsT0FBTyxDQUFDLE9BQU8sQ0FBQztnQkFDZCxPQUFPLEVBQUUsSUFBSTtnQkFDYixNQUFNLEVBQUU7b0JBQ04sSUFBSSxFQUFFLGNBQWM7b0JBQ3BCLEdBQUcsRUFBRSwrQ0FBK0M7aUJBQ3JEO2FBQ0YsQ0FBQztTQUNMLENBQUMsQ0FBQTtRQUVGLFNBQVMsQ0FBQyxxQkFBcUIsQ0FBQztZQUM5QixFQUFFLEVBQUUsSUFBSTtZQUNSLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FDVCxPQUFPLENBQUMsT0FBTyxDQUFDO2dCQUNkLE9BQU8sRUFBRSxJQUFJO2dCQUNiLE1BQU0sRUFBRTtvQkFDTixFQUFFLEVBQUUsWUFBWTtvQkFDaEIsR0FBRyxFQUFFLG1FQUFtRTtpQkFDekU7YUFDRixDQUFDO1NBQ0wsQ0FBQyxDQUFBO1FBRUYsU0FBUyxDQUFDLHFCQUFxQixDQUFDO1lBQzlCLEVBQUUsRUFBRSxJQUFJO1lBQ1IsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUNULE9BQU8sQ0FBQyxPQUFPLENBQUM7Z0JBQ2QsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsTUFBTSxFQUFFO29CQUNOLEVBQUUsRUFBRSxZQUFZO29CQUNoQixHQUFHLEVBQUUsbUVBQW1FO2lCQUN6RTthQUNGLENBQUM7U0FDTCxDQUFDLENBQUE7UUFFRixNQUFNLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsQ0FBQTtRQUVqRCxNQUFNLGtCQUFrQixHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ2xELE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFBO1FBQ3hDLElBQUksQ0FBQyxrQkFBa0I7WUFBRSxPQUFNO1FBRS9CLE1BQU0sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FDbkMsdURBQXVELENBQ3hELENBQUE7UUFDRCxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUM7WUFDMUMsTUFBTSxFQUFFLE1BQU07WUFDZCxPQUFPLEVBQUU7Z0JBQ1AsYUFBYSxFQUFFLGNBQWM7YUFDOUI7U0FDRixDQUFDLENBQUE7UUFFRixNQUFNLFFBQVEsR0FBRyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUE7UUFDM0MsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQTtRQUMxRCxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQTtJQUNsRCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyxtQ0FBbUMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNqRCxTQUFTLENBQUMscUJBQXFCLENBQUM7WUFDOUIsRUFBRSxFQUFFLElBQUk7WUFDUixJQUFJLEVBQUUsR0FBRyxFQUFFLENBQ1QsT0FBTyxDQUFDLE9BQU8sQ0FBQztnQkFDZCxPQUFPLEVBQUUsSUFBSTtnQkFDYixNQUFNLEVBQUU7b0JBQ04sSUFBSSxFQUFFLGNBQWM7b0JBQ3BCLEdBQUcsRUFBRSwrQ0FBK0M7aUJBQ3JEO2FBQ0YsQ0FBQztTQUNMLENBQUMsQ0FBQTtRQUVGLFNBQVMsQ0FBQyxxQkFBcUIsQ0FBQztZQUM5QixFQUFFLEVBQUUsSUFBSTtZQUNSLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FDVCxPQUFPLENBQUMsT0FBTyxDQUFDO2dCQUNkLE9BQU8sRUFBRSxJQUFJO2dCQUNiLE1BQU0sRUFBRTtvQkFDTixFQUFFLEVBQUUsWUFBWTtvQkFDaEIsR0FBRyxFQUFFLG1FQUFtRTtpQkFDekU7YUFDRixDQUFDO1NBQ0wsQ0FBQyxDQUFBO1FBRUYsU0FBUyxDQUFDLHFCQUFxQixDQUFDO1lBQzlCLEVBQUUsRUFBRSxJQUFJO1lBQ1IsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUNULE9BQU8sQ0FBQyxPQUFPLENBQUM7Z0JBQ2QsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsTUFBTSxFQUFFO29CQUNOLEVBQUUsRUFBRSxZQUFZO29CQUNoQixHQUFHLEVBQUUsbUVBQW1FO2lCQUN6RTthQUNGLENBQUM7U0FDTCxDQUFDLENBQUE7UUFFRixNQUFNLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsQ0FBQTtRQUVqRCxNQUFNLHFCQUFxQixHQUFHLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ3JELE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFBO1FBQzNDLElBQUksQ0FBQyxxQkFBcUI7WUFBRSxPQUFNO1FBRWxDLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FDdEMsdURBQXVELENBQ3hELENBQUE7UUFFRCxNQUFNLFFBQVEsR0FBRyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUE7UUFDOUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsQ0FBQTtRQUMxRCxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQyxDQUFBO1FBRXhELE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUE7UUFDekMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUN6QyxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQyx3Q0FBd0MsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN0RCxTQUFTLENBQUMscUJBQXFCLENBQUM7WUFDOUIsRUFBRSxFQUFFLEtBQUs7WUFDVCxNQUFNLEVBQUUsR0FBRztZQUNYLFVBQVUsRUFBRSxhQUFhO1lBQ3pCLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLHNCQUFzQixDQUFDO1NBQ3BELENBQUMsQ0FBQTtRQUVGLE1BQU0sTUFBTSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQ3ZFLGlDQUFpQyxDQUNsQyxDQUFBO0lBQ0gsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMseUNBQXlDLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDdkQsU0FBUyxDQUFDLHFCQUFxQixDQUFDO1lBQzlCLEVBQUUsRUFBRSxJQUFJO1lBQ1IsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUNULE9BQU8sQ0FBQyxPQUFPLENBQUM7Z0JBQ2QsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsTUFBTSxFQUFFO29CQUNOLElBQUksRUFBRSxjQUFjO29CQUNwQixHQUFHLEVBQUUsK0NBQStDO2lCQUNyRDthQUNGLENBQUM7U0FDTCxDQUFDLENBQUE7UUFFRixTQUFTLENBQUMscUJBQXFCLENBQUM7WUFDOUIsRUFBRSxFQUFFLEtBQUs7WUFDVCxNQUFNLEVBQUUsR0FBRztZQUNYLFVBQVUsRUFBRSx1QkFBdUI7WUFDbkMsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsMkJBQTJCLENBQUM7U0FDekQsQ0FBQyxDQUFBO1FBRUYsTUFBTSxNQUFNLENBQUMsaUJBQWlCLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FDdkUsMkNBQTJDLENBQzVDLENBQUE7SUFDSCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQywyQ0FBMkMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN6RCxTQUFTLENBQUMscUJBQXFCLENBQUM7WUFDOUIsRUFBRSxFQUFFLElBQUk7WUFDUixJQUFJLEVBQUUsR0FBRyxFQUFFLENBQ1QsT0FBTyxDQUFDLE9BQU8sQ0FBQztnQkFDZCxPQUFPLEVBQUUsS0FBSztnQkFDZCxLQUFLLEVBQUU7b0JBQ0wsT0FBTyxFQUFFLHdCQUF3QjtpQkFDbEM7YUFDRixDQUFDO1NBQ0wsQ0FBQyxDQUFBO1FBRUYsTUFBTSxNQUFNLENBQUMsaUJBQWlCLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FDdkUsZ0JBQWdCLENBQ2pCLENBQUE7SUFDSCxDQUFDLENBQUMsQ0FBQTtJQUVGLEVBQUUsQ0FBQywwQ0FBMEMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN4RCxNQUFNLG9CQUFvQixHQUFZO1lBQ3BDLEdBQUcsV0FBVztZQUNkLFNBQVMsRUFBRTtnQkFDVDtvQkFDRSxJQUFJLEVBQUUsWUFBWTtvQkFDbEIsSUFBSSxFQUFFLGNBQWMsQ0FBQyxVQUFVLENBQUM7b0JBQ2hDLE1BQU0sRUFBRSxLQUFLO2lCQUNkO2dCQUNEO29CQUNFLElBQUksRUFBRSxZQUFZO29CQUNsQixJQUFJLEVBQUUsY0FBYyxDQUFDLFVBQVUsQ0FBQztvQkFDaEMsTUFBTSxFQUFFLE1BQU07aUJBQ2Y7YUFDRjtTQUNGLENBQUE7UUFFRCxTQUFTLENBQUMsaUJBQWlCLENBQUM7WUFDMUIsRUFBRSxFQUFFLElBQUk7WUFDUixJQUFJLEVBQUUsR0FBRyxFQUFFLENBQ1QsT0FBTyxDQUFDLE9BQU8sQ0FBQztnQkFDZCxPQUFPLEVBQUUsSUFBSTtnQkFDYixNQUFNLEVBQUU7b0JBQ04sSUFBSSxFQUFFLGNBQWM7b0JBQ3BCLEdBQUcsRUFBRSwrQ0FBK0M7aUJBQ3JEO2FBQ0YsQ0FBQztTQUNMLENBQUMsQ0FBQTtRQUVGLE1BQU0saUJBQWlCLENBQUMsb0JBQW9CLEVBQUUsV0FBVyxDQUFDLENBQUE7UUFFMUQsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxDQUFBO1FBRTFDLE1BQU0sa0JBQWtCLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDbEQsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUMsV0FBVyxFQUFFLENBQUE7UUFDeEMsSUFBSSxDQUFDLGtCQUFrQjtZQUFFLE9BQU07UUFFL0IsTUFBTSxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUNuQyx1REFBdUQsQ0FDeEQsQ0FBQTtJQUNILENBQUMsQ0FBQyxDQUFBO0lBRUYsRUFBRSxDQUFDLG9DQUFvQyxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ2xELE1BQU0sWUFBWSxHQUFZO1lBQzVCLEdBQUcsV0FBVztZQUNkLFNBQVMsRUFBRSxFQUFFO1NBQ2QsQ0FBQTtRQUVELFNBQVMsQ0FBQyxxQkFBcUIsQ0FBQztZQUM5QixFQUFFLEVBQUUsSUFBSTtZQUNSLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FDVCxPQUFPLENBQUMsT0FBTyxDQUFDO2dCQUNkLE9BQU8sRUFBRSxJQUFJO2dCQUNiLE1BQU0sRUFBRTtvQkFDTixJQUFJLEVBQUUsY0FBYztvQkFDcEIsR0FBRyxFQUFFLCtDQUErQztpQkFDckQ7YUFDRixDQUFDO1NBQ0wsQ0FBQyxDQUFBO1FBRUYsU0FBUyxDQUFDLHFCQUFxQixDQUFDO1lBQzlCLEVBQUUsRUFBRSxJQUFJO1lBQ1IsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUNULE9BQU8sQ0FBQyxPQUFPLENBQUM7Z0JBQ2QsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsTUFBTSxFQUFFO29CQUNOLEVBQUUsRUFBRSxZQUFZO29CQUNoQixHQUFHLEVBQUUsbUVBQW1FO2lCQUN6RTthQUNGLENBQUM7U0FDTCxDQUFDLENBQUE7UUFFRixNQUFNLE1BQU0sR0FBRyxNQUFNLGlCQUFpQixDQUFDLFlBQVksRUFBRSxXQUFXLENBQUMsQ0FBQTtRQUVqRSxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDMUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxPQUFPLENBQy9CLCtDQUErQyxDQUNoRCxDQUFBO0lBQ0gsQ0FBQyxDQUFDLENBQUE7SUFFRixFQUFFLENBQUMsd0NBQXdDLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDdEQsU0FBUyxDQUFDLGlCQUFpQixDQUFDO1lBQzFCLEVBQUUsRUFBRSxJQUFJO1lBQ1IsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUNULE9BQU8sQ0FBQyxPQUFPLENBQUM7Z0JBQ2QsT0FBTyxFQUFFLElBQUk7Z0JBQ2IsTUFBTSxFQUFFLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRTthQUNqQyxDQUFDO1NBQ0wsQ0FBQyxDQUFBO1FBRUYsTUFBTSxpQkFBaUIsQ0FBQyxXQUFXLEVBQUU7WUFDbkMsR0FBRyxXQUFXO1lBQ2QsTUFBTSxFQUFFLGdCQUFnQjtTQUN6QixDQUFDLENBQUE7UUFFRixNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUN6QyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUE7UUFDL0IsSUFBSSxDQUFDLFNBQVM7WUFBRSxPQUFNO1FBRXRCLE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUE7UUFDcEMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQTtJQUN6RCxDQUFDLENBQUMsQ0FBQTtBQUNKLENBQUMsQ0FBQyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmVsYXRpdmUgfSBmcm9tIFwibm9kZTpwYXRoXCJcbmltcG9ydCB0eXBlIHsgUGFja2FnZSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7IGxvYWRQYWNrYWdlRGVzY3JpcHRvciB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7IGFmdGVyRWFjaCwgYmVmb3JlRWFjaCwgZGVzY3JpYmUsIGV4cGVjdCwgaXQsIHZpIH0gZnJvbSBcInZpdGVzdFwiXG5pbXBvcnQgeyBzYXZlUGFja2FnZVRvQ2thbiB9IGZyb20gXCIuL3NhdmUudHNcIlxuXG5kZXNjcmliZShcInNhdmVQYWNrYWdlVG9Da2FuXCIsICgpID0+IHtcbiAgY29uc3QgZ2V0Rml4dHVyZVBhdGggPSAobmFtZTogc3RyaW5nKSA9PlxuICAgIHJlbGF0aXZlKHByb2Nlc3MuY3dkKCksIGAke2ltcG9ydC5tZXRhLmRpcm5hbWV9L2ZpeHR1cmVzLyR7bmFtZX1gKVxuXG4gIGNvbnN0IG1vY2tQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgdGl0bGU6IFwiVGVzdCBQYWNrYWdlXCIsXG4gICAgZGVzY3JpcHRpb246IFwiQSB0ZXN0IHBhY2thZ2VcIixcbiAgICB2ZXJzaW9uOiBcIjEuMC4wXCIsXG4gICAgcmVzb3VyY2VzOiBbXG4gICAgICB7XG4gICAgICAgIG5hbWU6IFwidGVzdC1yZXNvdXJjZVwiLFxuICAgICAgICBwYXRoOiBnZXRGaXh0dXJlUGF0aChcImRhdGEuY3N2XCIpLFxuICAgICAgICBmb3JtYXQ6IFwiY3N2XCIsXG4gICAgICAgIGJ5dGVzOiAxMDAsXG4gICAgICB9LFxuICAgIF0sXG4gIH1cblxuICBjb25zdCBtb2NrT3B0aW9ucyA9IHtcbiAgICBhcGlLZXk6IFwidGVzdC1hcGkta2V5XCIsXG4gICAgY2thblVybDogXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb21cIixcbiAgICBvd25lck9yZzogXCJ0ZXN0LW9yZ1wiLFxuICAgIGRhdGFzZXROYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICB9XG5cbiAgY29uc3Qgb3JpZ2luYWxGZXRjaCA9IGdsb2JhbFRoaXMuZmV0Y2hcbiAgbGV0IGZldGNoTW9jazogUmV0dXJuVHlwZTx0eXBlb2YgdmkuZm4+XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgZmV0Y2hNb2NrID0gdmkuZm4oKVxuICAgIC8vIEB0cy1pZ25vcmVcbiAgICBnbG9iYWxUaGlzLmZldGNoID0gZmV0Y2hNb2NrXG4gIH0pXG5cbiAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICBnbG9iYWxUaGlzLmZldGNoID0gb3JpZ2luYWxGZXRjaFxuICAgIHZpLnJlc2V0QWxsTW9ja3MoKVxuICB9KVxuXG4gIGl0LnNraXAoXCJzaG91bGQgc2F2ZSBhIHBhY2thZ2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGRhdGFQYWNrYWdlID0gYXdhaXQgbG9hZFBhY2thZ2VEZXNjcmlwdG9yKFxuICAgICAgXCJjb3JlL3BhY2thZ2UvZml4dHVyZXMvcGFja2FnZS5qc29uXCIsXG4gICAgKVxuXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgc2F2ZVBhY2thZ2VUb0NrYW4oZGF0YVBhY2thZ2UsIHtcbiAgICAgIGNrYW5Vcmw6IFwiaHR0cDovL2xvY2FsaG9zdDo1MDAwL1wiLFxuICAgICAgYXBpS2V5OlxuICAgICAgICBcImV5SmhiR2NpT2lKSVV6STFOaUlzSW5SNWNDSTZJa3BYVkNKOS5leUpxZEdraU9pSjFUMFkwVlVOeWJUVTVZMGR6ZGxrM2VqaHJlRjlDZUMwMlIwdzRSREJPZFc5UVMwSjBXa0pGWHpsSklpd2lhV0YwSWpveE56UTNPVEkwTkRnNWZRLmlvR2lMbFprbTI0eEhRUkJhczVYNWlnNWVVN3VfZklqa2w0b2lmR25MYUFcIixcbiAgICAgIGRhdGFzZXROYW1lOiBcInRlc3RcIixcbiAgICAgIG93bmVyT3JnOiBcInRlc3RcIixcbiAgICB9KVxuXG4gICAgZXhwZWN0KHJlc3VsdCkudG9CZURlZmluZWQoKVxuICB9KVxuXG4gIGl0KFwiY3JlYXRlcyBhIHBhY2thZ2UgaW4gQ0tBTiB3aXRoIGNvcnJlY3QgQVBJIGNhbGxzXCIsIGFzeW5jICgpID0+IHtcbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgbmFtZTogXCJ0ZXN0LWRhdGFzZXRcIixcbiAgICAgICAgICAgIHVybDogXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICB9KVxuXG4gICAgZmV0Y2hNb2NrLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICBvazogdHJ1ZSxcbiAgICAgIGpzb246ICgpID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICByZXN1bHQ6IHtcbiAgICAgICAgICAgIGlkOiBcInJlc291cmNlLTFcIixcbiAgICAgICAgICAgIHVybDogXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXQvcmVzb3VyY2UvcmVzb3VyY2UtMVwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgaWQ6IFwicmVzb3VyY2UtMlwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS9yZXNvdXJjZS0yXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHNhdmVQYWNrYWdlVG9Da2FuKG1vY2tQYWNrYWdlLCBtb2NrT3B0aW9ucylcblxuICAgIGV4cGVjdChmZXRjaE1vY2spLnRvSGF2ZUJlZW5DYWxsZWRUaW1lcygzKVxuXG4gICAgY29uc3QgcGFja2FnZUNyZWF0ZUNhbGwgPSBmZXRjaE1vY2subW9jay5jYWxsc1swXVxuICAgIGV4cGVjdChwYWNrYWdlQ3JlYXRlQ2FsbCkudG9CZURlZmluZWQoKVxuICAgIGlmICghcGFja2FnZUNyZWF0ZUNhbGwpIHJldHVyblxuXG4gICAgZXhwZWN0KHBhY2thZ2VDcmVhdGVDYWxsWzBdKS50b0VxdWFsKFxuICAgICAgXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb20vYXBpLzMvYWN0aW9uL3BhY2thZ2VfY3JlYXRlXCIsXG4gICAgKVxuICAgIGV4cGVjdChwYWNrYWdlQ3JlYXRlQ2FsbFsxXSkudG9NYXRjaE9iamVjdCh7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICBBdXRob3JpemF0aW9uOiBcInRlc3QtYXBpLWtleVwiLFxuICAgICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgIH0sXG4gICAgfSlcblxuICAgIGNvbnN0IHBhY2thZ2VQYXlsb2FkID0gSlNPTi5wYXJzZShwYWNrYWdlQ3JlYXRlQ2FsbFsxXS5ib2R5KVxuICAgIGV4cGVjdChwYWNrYWdlUGF5bG9hZC5uYW1lKS50b0VxdWFsKFwidGVzdC1kYXRhc2V0XCIpXG4gICAgZXhwZWN0KHBhY2thZ2VQYXlsb2FkLm93bmVyX29yZykudG9FcXVhbChcInRlc3Qtb3JnXCIpXG4gICAgZXhwZWN0KHBhY2thZ2VQYXlsb2FkLnRpdGxlKS50b0VxdWFsKFwiVGVzdCBQYWNrYWdlXCIpXG4gICAgZXhwZWN0KHBhY2thZ2VQYXlsb2FkLm5vdGVzKS50b0VxdWFsKFwiQSB0ZXN0IHBhY2thZ2VcIilcbiAgICBleHBlY3QocGFja2FnZVBheWxvYWQucmVzb3VyY2VzKS50b0VxdWFsKFtdKVxuXG4gICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbCh7XG4gICAgICBwYXRoOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgZGF0YXNldFVybDogXCJodHRwczovL2NrYW4uZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICB9KVxuICB9KVxuXG4gIGl0KFwiY3JlYXRlcyByZXNvdXJjZXMgd2l0aCBmaWxlIHVwbG9hZHNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBuYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgaWQ6IFwicmVzb3VyY2UtMVwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS9yZXNvdXJjZS0xXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBpZDogXCJyZXNvdXJjZS0yXCIsXG4gICAgICAgICAgICB1cmw6IFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0L3Jlc291cmNlL3Jlc291cmNlLTJcIixcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICB9KVxuXG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VUb0NrYW4obW9ja1BhY2thZ2UsIG1vY2tPcHRpb25zKVxuXG4gICAgY29uc3QgcmVzb3VyY2VDcmVhdGVDYWxsID0gZmV0Y2hNb2NrLm1vY2suY2FsbHNbMV1cbiAgICBleHBlY3QocmVzb3VyY2VDcmVhdGVDYWxsKS50b0JlRGVmaW5lZCgpXG4gICAgaWYgKCFyZXNvdXJjZUNyZWF0ZUNhbGwpIHJldHVyblxuXG4gICAgZXhwZWN0KHJlc291cmNlQ3JlYXRlQ2FsbFswXSkudG9FcXVhbChcbiAgICAgIFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2FwaS8zL2FjdGlvbi9yZXNvdXJjZV9jcmVhdGVcIixcbiAgICApXG4gICAgZXhwZWN0KHJlc291cmNlQ3JlYXRlQ2FsbFsxXSkudG9NYXRjaE9iamVjdCh7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICBBdXRob3JpemF0aW9uOiBcInRlc3QtYXBpLWtleVwiLFxuICAgICAgfSxcbiAgICB9KVxuXG4gICAgY29uc3QgZm9ybURhdGEgPSByZXNvdXJjZUNyZWF0ZUNhbGxbMV0uYm9keVxuICAgIGV4cGVjdChmb3JtRGF0YSkudG9CZUluc3RhbmNlT2YoRm9ybURhdGEpXG4gICAgZXhwZWN0KGZvcm1EYXRhLmdldChcInBhY2thZ2VfaWRcIikpLnRvRXF1YWwoXCJ0ZXN0LWRhdGFzZXRcIilcbiAgICBleHBlY3QoZm9ybURhdGEuZ2V0KFwibmFtZVwiKSkudG9FcXVhbChcImRhdGEuY3N2XCIpXG4gIH0pXG5cbiAgaXQoXCJjcmVhdGVzIGRhdGFwYWNrYWdlLmpzb24gcmVzb3VyY2VcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBuYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgaWQ6IFwicmVzb3VyY2UtMVwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS9yZXNvdXJjZS0xXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBpZDogXCJyZXNvdXJjZS0yXCIsXG4gICAgICAgICAgICB1cmw6IFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0L3Jlc291cmNlL3Jlc291cmNlLTJcIixcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICB9KVxuXG4gICAgYXdhaXQgc2F2ZVBhY2thZ2VUb0NrYW4obW9ja1BhY2thZ2UsIG1vY2tPcHRpb25zKVxuXG4gICAgY29uc3QgZGF0YXBhY2thZ2VDcmVhdGVDYWxsID0gZmV0Y2hNb2NrLm1vY2suY2FsbHNbMl1cbiAgICBleHBlY3QoZGF0YXBhY2thZ2VDcmVhdGVDYWxsKS50b0JlRGVmaW5lZCgpXG4gICAgaWYgKCFkYXRhcGFja2FnZUNyZWF0ZUNhbGwpIHJldHVyblxuXG4gICAgZXhwZWN0KGRhdGFwYWNrYWdlQ3JlYXRlQ2FsbFswXSkudG9FcXVhbChcbiAgICAgIFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2FwaS8zL2FjdGlvbi9yZXNvdXJjZV9jcmVhdGVcIixcbiAgICApXG5cbiAgICBjb25zdCBmb3JtRGF0YSA9IGRhdGFwYWNrYWdlQ3JlYXRlQ2FsbFsxXS5ib2R5XG4gICAgZXhwZWN0KGZvcm1EYXRhKS50b0JlSW5zdGFuY2VPZihGb3JtRGF0YSlcbiAgICBleHBlY3QoZm9ybURhdGEuZ2V0KFwicGFja2FnZV9pZFwiKSkudG9FcXVhbChcInRlc3QtZGF0YXNldFwiKVxuICAgIGV4cGVjdChmb3JtRGF0YS5nZXQoXCJuYW1lXCIpKS50b0VxdWFsKFwiZGF0YXBhY2thZ2UuanNvblwiKVxuXG4gICAgY29uc3QgdXBsb2FkQmxvYiA9IGZvcm1EYXRhLmdldChcInVwbG9hZFwiKVxuICAgIGV4cGVjdCh1cGxvYWRCbG9iKS50b0JlSW5zdGFuY2VPZihCbG9iKVxuICB9KVxuXG4gIGl0KFwiaGFuZGxlcyBBUEkgZXJyb3JzIGZyb20gcGFja2FnZV9jcmVhdGVcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IGZhbHNlLFxuICAgICAgc3RhdHVzOiA0MDAsXG4gICAgICBzdGF0dXNUZXh0OiBcIkJhZCBSZXF1ZXN0XCIsXG4gICAgICB0ZXh0OiAoKSA9PiBQcm9taXNlLnJlc29sdmUoXCJJbnZhbGlkIHBhY2thZ2UgZGF0YVwiKSxcbiAgICB9KVxuXG4gICAgYXdhaXQgZXhwZWN0KHNhdmVQYWNrYWdlVG9Da2FuKG1vY2tQYWNrYWdlLCBtb2NrT3B0aW9ucykpLnJlamVjdHMudG9UaHJvdyhcbiAgICAgIFwiQ0tBTiBBUEkgZXJyb3I6IDQwMCBCYWQgUmVxdWVzdFwiLFxuICAgIClcbiAgfSlcblxuICBpdChcImhhbmRsZXMgQVBJIGVycm9ycyBmcm9tIHJlc291cmNlX2NyZWF0ZVwiLCBhc3luYyAoKSA9PiB7XG4gICAgZmV0Y2hNb2NrLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICBvazogdHJ1ZSxcbiAgICAgIGpzb246ICgpID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICByZXN1bHQ6IHtcbiAgICAgICAgICAgIG5hbWU6IFwidGVzdC1kYXRhc2V0XCIsXG4gICAgICAgICAgICB1cmw6IFwiaHR0cHM6Ly9ja2FuLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0XCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IGZhbHNlLFxuICAgICAgc3RhdHVzOiA1MDAsXG4gICAgICBzdGF0dXNUZXh0OiBcIkludGVybmFsIFNlcnZlciBFcnJvclwiLFxuICAgICAgdGV4dDogKCkgPT4gUHJvbWlzZS5yZXNvbHZlKFwiRmFpbGVkIHRvIGNyZWF0ZSByZXNvdXJjZVwiKSxcbiAgICB9KVxuXG4gICAgYXdhaXQgZXhwZWN0KHNhdmVQYWNrYWdlVG9Da2FuKG1vY2tQYWNrYWdlLCBtb2NrT3B0aW9ucykpLnJlamVjdHMudG9UaHJvdyhcbiAgICAgIFwiQ0tBTiBBUEkgZXJyb3I6IDUwMCBJbnRlcm5hbCBTZXJ2ZXIgRXJyb3JcIixcbiAgICApXG4gIH0pXG5cbiAgaXQoXCJoYW5kbGVzIENLQU4gQVBJIHN1Y2Nlc3M6IGZhbHNlIHJlc3BvbnNlc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgZmV0Y2hNb2NrLm1vY2tSZXNvbHZlZFZhbHVlT25jZSh7XG4gICAgICBvazogdHJ1ZSxcbiAgICAgIGpzb246ICgpID0+XG4gICAgICAgIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgZXJyb3I6IHtcbiAgICAgICAgICAgIG1lc3NhZ2U6IFwiUGFja2FnZSBhbHJlYWR5IGV4aXN0c1wiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBhd2FpdCBleHBlY3Qoc2F2ZVBhY2thZ2VUb0NrYW4obW9ja1BhY2thZ2UsIG1vY2tPcHRpb25zKSkucmVqZWN0cy50b1Rocm93KFxuICAgICAgXCJDS0FOIEFQSSBlcnJvclwiLFxuICAgIClcbiAgfSlcblxuICBpdChcImhhbmRsZXMgcGFja2FnZXMgd2l0aCBtdWx0aXBsZSByZXNvdXJjZXNcIiwgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IG11bHRpUmVzb3VyY2VQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgLi4ubW9ja1BhY2thZ2UsXG4gICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6IFwicmVzb3VyY2UtMVwiLFxuICAgICAgICAgIHBhdGg6IGdldEZpeHR1cmVQYXRoKFwiZGF0YS5jc3ZcIiksXG4gICAgICAgICAgZm9ybWF0OiBcImNzdlwiLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogXCJyZXNvdXJjZS0yXCIsXG4gICAgICAgICAgcGF0aDogZ2V0Rml4dHVyZVBhdGgoXCJkYXRhLmNzdlwiKSxcbiAgICAgICAgICBmb3JtYXQ6IFwianNvblwiLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9XG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBuYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBhd2FpdCBzYXZlUGFja2FnZVRvQ2thbihtdWx0aVJlc291cmNlUGFja2FnZSwgbW9ja09wdGlvbnMpXG5cbiAgICBleHBlY3QoZmV0Y2hNb2NrKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoNClcblxuICAgIGNvbnN0IHNlY29uZFJlc291cmNlQ2FsbCA9IGZldGNoTW9jay5tb2NrLmNhbGxzWzJdXG4gICAgZXhwZWN0KHNlY29uZFJlc291cmNlQ2FsbCkudG9CZURlZmluZWQoKVxuICAgIGlmICghc2Vjb25kUmVzb3VyY2VDYWxsKSByZXR1cm5cblxuICAgIGV4cGVjdChzZWNvbmRSZXNvdXJjZUNhbGxbMF0pLnRvRXF1YWwoXG4gICAgICBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9hcGkvMy9hY3Rpb24vcmVzb3VyY2VfY3JlYXRlXCIsXG4gICAgKVxuICB9KVxuXG4gIGl0KFwiaGFuZGxlcyBwYWNrYWdlcyB3aXRoIG5vIHJlc291cmNlc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZW1wdHlQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgLi4ubW9ja1BhY2thZ2UsXG4gICAgICByZXNvdXJjZXM6IFtdLFxuICAgIH1cblxuICAgIGZldGNoTW9jay5tb2NrUmVzb2x2ZWRWYWx1ZU9uY2Uoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7XG4gICAgICAgICAgICBuYW1lOiBcInRlc3QtZGF0YXNldFwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgIH0pXG5cbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWVPbmNlKHtcbiAgICAgIG9rOiB0cnVlLFxuICAgICAganNvbjogKCkgPT5cbiAgICAgICAgUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgICAgIHJlc3VsdDoge1xuICAgICAgICAgICAgaWQ6IFwicmVzb3VyY2UtMVwiLFxuICAgICAgICAgICAgdXJsOiBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS9yZXNvdXJjZS0xXCIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHNhdmVQYWNrYWdlVG9Da2FuKGVtcHR5UGFja2FnZSwgbW9ja09wdGlvbnMpXG5cbiAgICBleHBlY3QoZmV0Y2hNb2NrKS50b0hhdmVCZWVuQ2FsbGVkVGltZXMoMilcbiAgICBleHBlY3QocmVzdWx0LmRhdGFzZXRVcmwpLnRvRXF1YWwoXG4gICAgICBcImh0dHBzOi8vY2thbi5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldFwiLFxuICAgIClcbiAgfSlcblxuICBpdChcInBhc3NlcyBBUEkga2V5IGluIEF1dGhvcml6YXRpb24gaGVhZGVyXCIsIGFzeW5jICgpID0+IHtcbiAgICBmZXRjaE1vY2subW9ja1Jlc29sdmVkVmFsdWUoe1xuICAgICAgb2s6IHRydWUsXG4gICAgICBqc29uOiAoKSA9PlxuICAgICAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgcmVzdWx0OiB7IG5hbWU6IFwidGVzdC1kYXRhc2V0XCIgfSxcbiAgICAgICAgfSksXG4gICAgfSlcblxuICAgIGF3YWl0IHNhdmVQYWNrYWdlVG9Da2FuKG1vY2tQYWNrYWdlLCB7XG4gICAgICAuLi5tb2NrT3B0aW9ucyxcbiAgICAgIGFwaUtleTogXCJjdXN0b20tYXBpLWtleVwiLFxuICAgIH0pXG5cbiAgICBjb25zdCBmaXJzdENhbGwgPSBmZXRjaE1vY2subW9jay5jYWxsc1swXVxuICAgIGV4cGVjdChmaXJzdENhbGwpLnRvQmVEZWZpbmVkKClcbiAgICBpZiAoIWZpcnN0Q2FsbCkgcmV0dXJuXG5cbiAgICBjb25zdCBoZWFkZXJzID0gZmlyc3RDYWxsWzFdLmhlYWRlcnNcbiAgICBleHBlY3QoaGVhZGVycy5BdXRob3JpemF0aW9uKS50b0VxdWFsKFwiY3VzdG9tLWFwaS1rZXlcIilcbiAgfSlcbn0pXG4iXX0=
@@ -0,0 +1,19 @@
1
+ import type { DatasetPlugin } from "../../plugin.ts";
2
+ export declare class CkanPlugin implements DatasetPlugin {
3
+ loadPackage(source: string): Promise<{
4
+ [x: `${string}:${string}`]: any;
5
+ $schema?: string;
6
+ resources: import("@frictionless-ts/metadata").Resource[];
7
+ name?: string;
8
+ title?: string;
9
+ description?: string;
10
+ homepage?: string;
11
+ version?: string;
12
+ licenses?: import("@frictionless-ts/metadata").License[];
13
+ contributors?: import("@frictionless-ts/metadata").Contributor[];
14
+ sources?: import("@frictionless-ts/metadata").Source[];
15
+ keywords?: string[];
16
+ created?: string;
17
+ image?: string;
18
+ } | undefined>;
19
+ }
@@ -0,0 +1,18 @@
1
+ import { isRemotePath } from "@frictionless-ts/metadata";
2
+ import { loadPackageFromCkan } from "./package/load.js";
3
+ export class CkanPlugin {
4
+ async loadPackage(source) {
5
+ const isCkan = getIsCkan(source);
6
+ if (!isCkan)
7
+ return undefined;
8
+ const dataPackage = await loadPackageFromCkan(source);
9
+ return dataPackage;
10
+ }
11
+ }
12
+ function getIsCkan(path) {
13
+ const isRemote = isRemotePath(path);
14
+ if (!isRemote)
15
+ return false;
16
+ return path.includes("/dataset/");
17
+ }
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcGx1Z2lucy9ja2FuL3BsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFFeEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFdkQsTUFBTSxPQUFPLFVBQVU7SUFDckIsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFjO1FBQzlCLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQTtRQUNoQyxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU8sU0FBUyxDQUFBO1FBRTdCLE1BQU0sV0FBVyxHQUFHLE1BQU0sbUJBQW1CLENBQUMsTUFBTSxDQUFDLENBQUE7UUFDckQsT0FBTyxXQUFXLENBQUE7SUFDcEIsQ0FBQztDQUNGO0FBRUQsU0FBUyxTQUFTLENBQUMsSUFBWTtJQUM3QixNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUE7SUFDbkMsSUFBSSxDQUFDLFFBQVE7UUFBRSxPQUFPLEtBQUssQ0FBQTtJQUUzQixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUE7QUFDbkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGlzUmVtb3RlUGF0aCB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB0eXBlIHsgRGF0YXNldFBsdWdpbiB9IGZyb20gXCIuLi8uLi9wbHVnaW4udHNcIlxuaW1wb3J0IHsgbG9hZFBhY2thZ2VGcm9tQ2thbiB9IGZyb20gXCIuL3BhY2thZ2UvbG9hZC50c1wiXG5cbmV4cG9ydCBjbGFzcyBDa2FuUGx1Z2luIGltcGxlbWVudHMgRGF0YXNldFBsdWdpbiB7XG4gIGFzeW5jIGxvYWRQYWNrYWdlKHNvdXJjZTogc3RyaW5nKSB7XG4gICAgY29uc3QgaXNDa2FuID0gZ2V0SXNDa2FuKHNvdXJjZSlcbiAgICBpZiAoIWlzQ2thbikgcmV0dXJuIHVuZGVmaW5lZFxuXG4gICAgY29uc3QgZGF0YVBhY2thZ2UgPSBhd2FpdCBsb2FkUGFja2FnZUZyb21Da2FuKHNvdXJjZSlcbiAgICByZXR1cm4gZGF0YVBhY2thZ2VcbiAgfVxufVxuXG5mdW5jdGlvbiBnZXRJc0NrYW4ocGF0aDogc3RyaW5nKSB7XG4gIGNvbnN0IGlzUmVtb3RlID0gaXNSZW1vdGVQYXRoKHBhdGgpXG4gIGlmICghaXNSZW1vdGUpIHJldHVybiBmYWxzZVxuXG4gIHJldHVybiBwYXRoLmluY2x1ZGVzKFwiL2RhdGFzZXQvXCIpXG59XG4iXX0=
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,83 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import * as packageModule from "./package/load.js";
3
+ import { CkanPlugin } from "./plugin.js";
4
+ vi.mock("./package/load.ts", () => ({
5
+ loadPackageFromCkan: vi.fn(),
6
+ }));
7
+ describe("CkanPlugin", () => {
8
+ let plugin;
9
+ let mockLoadPackageFromCkan;
10
+ beforeEach(() => {
11
+ plugin = new CkanPlugin();
12
+ mockLoadPackageFromCkan = vi.mocked(packageModule.loadPackageFromCkan);
13
+ vi.clearAllMocks();
14
+ });
15
+ describe("loadPackage", () => {
16
+ it("should load package from ckan url with /dataset/ path", async () => {
17
+ const mockPackage = {
18
+ name: "test-package",
19
+ resources: [{ name: "test", data: [] }],
20
+ };
21
+ mockLoadPackageFromCkan.mockResolvedValue(mockPackage);
22
+ const result = await plugin.loadPackage("https://data.example.com/dataset/test-dataset");
23
+ expect(mockLoadPackageFromCkan).toHaveBeenCalledWith("https://data.example.com/dataset/test-dataset");
24
+ expect(result).toEqual(mockPackage);
25
+ });
26
+ it("should return undefined for urls without /dataset/", async () => {
27
+ const result = await plugin.loadPackage("https://example.com/data");
28
+ expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
29
+ expect(result).toBeUndefined();
30
+ });
31
+ it("should return undefined for local paths", async () => {
32
+ const result = await plugin.loadPackage("./data");
33
+ expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
34
+ expect(result).toBeUndefined();
35
+ });
36
+ it("should return undefined for github urls", async () => {
37
+ const result = await plugin.loadPackage("https://github.com/owner/repo");
38
+ expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
39
+ expect(result).toBeUndefined();
40
+ });
41
+ it("should handle ckan urls with additional path segments", async () => {
42
+ const mockPackage = {
43
+ name: "test-package",
44
+ resources: [{ name: "test", data: [] }],
45
+ };
46
+ mockLoadPackageFromCkan.mockResolvedValue(mockPackage);
47
+ const result = await plugin.loadPackage("https://data.example.com/dataset/test-dataset/resource/123");
48
+ expect(mockLoadPackageFromCkan).toHaveBeenCalledWith("https://data.example.com/dataset/test-dataset/resource/123");
49
+ expect(result).toEqual(mockPackage);
50
+ });
51
+ it("should handle ckan urls with query parameters", async () => {
52
+ const mockPackage = {
53
+ name: "test-package",
54
+ resources: [{ name: "test", data: [] }],
55
+ };
56
+ mockLoadPackageFromCkan.mockResolvedValue(mockPackage);
57
+ const result = await plugin.loadPackage("https://data.example.com/dataset/test-dataset?id=456");
58
+ expect(mockLoadPackageFromCkan).toHaveBeenCalledWith("https://data.example.com/dataset/test-dataset?id=456");
59
+ expect(result).toEqual(mockPackage);
60
+ });
61
+ it("should handle http ckan urls", async () => {
62
+ const mockPackage = {
63
+ name: "test-package",
64
+ resources: [{ name: "test", data: [] }],
65
+ };
66
+ mockLoadPackageFromCkan.mockResolvedValue(mockPackage);
67
+ const result = await plugin.loadPackage("http://data.example.com/dataset/test-dataset");
68
+ expect(mockLoadPackageFromCkan).toHaveBeenCalledWith("http://data.example.com/dataset/test-dataset");
69
+ expect(result).toEqual(mockPackage);
70
+ });
71
+ it("should return undefined for zenodo urls", async () => {
72
+ const result = await plugin.loadPackage("https://zenodo.org/record/123");
73
+ expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
74
+ expect(result).toBeUndefined();
75
+ });
76
+ it("should return undefined for urls with dataset in query params only", async () => {
77
+ const result = await plugin.loadPackage("https://example.com/api?name=dataset");
78
+ expect(mockLoadPackageFromCkan).not.toHaveBeenCalled();
79
+ expect(result).toBeUndefined();
80
+ });
81
+ });
82
+ });
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2luLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wbHVnaW5zL2NrYW4vcGx1Z2luLnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsTUFBTSxRQUFRLENBQUE7QUFDN0QsT0FBTyxLQUFLLGFBQWEsTUFBTSxtQkFBbUIsQ0FBQTtBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBRXhDLEVBQUUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNsQyxtQkFBbUIsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO0NBQzdCLENBQUMsQ0FBQyxDQUFBO0FBRUgsUUFBUSxDQUFDLFlBQVksRUFBRSxHQUFHLEVBQUU7SUFDMUIsSUFBSSxNQUFrQixDQUFBO0lBQ3RCLElBQUksdUJBQWlELENBQUE7SUFFckQsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNkLE1BQU0sR0FBRyxJQUFJLFVBQVUsRUFBRSxDQUFBO1FBQ3pCLHVCQUF1QixHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLG1CQUFtQixDQUFDLENBQUE7UUFDdEUsRUFBRSxDQUFDLGFBQWEsRUFBRSxDQUFBO0lBQ3BCLENBQUMsQ0FBQyxDQUFBO0lBRUYsUUFBUSxDQUFDLGFBQWEsRUFBRSxHQUFHLEVBQUU7UUFDM0IsRUFBRSxDQUFDLHVEQUF1RCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ3JFLE1BQU0sV0FBVyxHQUFZO2dCQUMzQixJQUFJLEVBQUUsY0FBYztnQkFDcEIsU0FBUyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQzthQUN4QyxDQUFBO1lBQ0QsdUJBQXVCLENBQUMsaUJBQWlCLENBQUMsV0FBVyxD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ZSB9IGZyb20gXCJAZnJpY3Rpb25sZXNzLXRzL21ldGFkYXRhXCJcbmltcG9ydCB7IGJlZm9yZUVhY2gsIGRlc2NyaWJlLCBleHBlY3QsIGl0LCB2aSB9IGZyb20gXCJ2aXRlc3RcIlxuaW1wb3J0ICogYXMgcGFja2FnZU1vZHVsZSBmcm9tIFwiLi9wYWNrYWdlL2xvYWQudHNcIlxuaW1wb3J0IHsgQ2thblBsdWdpbiB9IGZyb20gXCIuL3BsdWdpbi50c1wiXG5cbnZpLm1vY2soXCIuL3BhY2thZ2UvbG9hZC50c1wiLCAoKSA9PiAoe1xuICBsb2FkUGFja2FnZUZyb21Da2FuOiB2aS5mbigpLFxufSkpXG5cbmRlc2NyaWJlKFwiQ2thblBsdWdpblwiLCAoKSA9PiB7XG4gIGxldCBwbHVnaW46IENrYW5QbHVnaW5cbiAgbGV0IG1vY2tMb2FkUGFja2FnZUZyb21Da2FuOiBSZXR1cm5UeXBlPHR5cGVvZiB2aS5mbj5cblxuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBwbHVnaW4gPSBuZXcgQ2thblBsdWdpbigpXG4gICAgbW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4gPSB2aS5tb2NrZWQocGFja2FnZU1vZHVsZS5sb2FkUGFja2FnZUZyb21Da2FuKVxuICAgIHZpLmNsZWFyQWxsTW9ja3MoKVxuICB9KVxuXG4gIGRlc2NyaWJlKFwibG9hZFBhY2thZ2VcIiwgKCkgPT4ge1xuICAgIGl0KFwic2hvdWxkIGxvYWQgcGFja2FnZSBmcm9tIGNrYW4gdXJsIHdpdGggL2RhdGFzZXQvIHBhdGhcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgbW9ja1BhY2thZ2U6IFBhY2thZ2UgPSB7XG4gICAgICAgIG5hbWU6IFwidGVzdC1wYWNrYWdlXCIsXG4gICAgICAgIHJlc291cmNlczogW3sgbmFtZTogXCJ0ZXN0XCIsIGRhdGE6IFtdIH1dLFxuICAgICAgfVxuICAgICAgbW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4ubW9ja1Jlc29sdmVkVmFsdWUobW9ja1BhY2thZ2UpXG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcbiAgICAgICAgXCJodHRwczovL2RhdGEuZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICAgIClcblxuICAgICAgZXhwZWN0KG1vY2tMb2FkUGFja2FnZUZyb21Da2FuKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgXCJodHRwczovL2RhdGEuZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIHVybHMgd2l0aG91dCAvZGF0YXNldC9cIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmxvYWRQYWNrYWdlKFwiaHR0cHM6Ly9leGFtcGxlLmNvbS9kYXRhXCIpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tQ2thbikubm90LnRvSGF2ZUJlZW5DYWxsZWQoKVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZVVuZGVmaW5lZCgpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIGxvY2FsIHBhdGhzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcIi4vZGF0YVwiKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4pLm5vdC50b0hhdmVCZWVuQ2FsbGVkKClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVVbmRlZmluZWQoKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCByZXR1cm4gdW5kZWZpbmVkIGZvciBnaXRodWIgdXJsc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFBhY2thZ2UoXCJodHRwczovL2dpdGh1Yi5jb20vb3duZXIvcmVwb1wiKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4pLm5vdC50b0hhdmVCZWVuQ2FsbGVkKClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvQmVVbmRlZmluZWQoKVxuICAgIH0pXG5cbiAgICBpdChcInNob3VsZCBoYW5kbGUgY2thbiB1cmxzIHdpdGggYWRkaXRpb25hbCBwYXRoIHNlZ21lbnRzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgICByZXNvdXJjZXM6IFt7IG5hbWU6IFwidGVzdFwiLCBkYXRhOiBbXSB9XSxcbiAgICAgIH1cbiAgICAgIG1vY2tMb2FkUGFja2FnZUZyb21Da2FuLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tQYWNrYWdlKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFBhY2thZ2UoXG4gICAgICAgIFwiaHR0cHM6Ly9kYXRhLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0L3Jlc291cmNlLzEyM1wiLFxuICAgICAgKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4pLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBcImh0dHBzOi8vZGF0YS5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldC9yZXNvdXJjZS8xMjNcIixcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIGhhbmRsZSBja2FuIHVybHMgd2l0aCBxdWVyeSBwYXJhbWV0ZXJzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tQYWNrYWdlOiBQYWNrYWdlID0ge1xuICAgICAgICBuYW1lOiBcInRlc3QtcGFja2FnZVwiLFxuICAgICAgICByZXNvdXJjZXM6IFt7IG5hbWU6IFwidGVzdFwiLCBkYXRhOiBbXSB9XSxcbiAgICAgIH1cbiAgICAgIG1vY2tMb2FkUGFja2FnZUZyb21Da2FuLm1vY2tSZXNvbHZlZFZhbHVlKG1vY2tQYWNrYWdlKVxuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwbHVnaW4ubG9hZFBhY2thZ2UoXG4gICAgICAgIFwiaHR0cHM6Ly9kYXRhLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0P2lkPTQ1NlwiLFxuICAgICAgKVxuXG4gICAgICBleHBlY3QobW9ja0xvYWRQYWNrYWdlRnJvbUNrYW4pLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBcImh0dHBzOi8vZGF0YS5leGFtcGxlLmNvbS9kYXRhc2V0L3Rlc3QtZGF0YXNldD9pZD00NTZcIixcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIGhhbmRsZSBodHRwIGNrYW4gdXJsc1wiLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBtb2NrUGFja2FnZTogUGFja2FnZSA9IHtcbiAgICAgICAgbmFtZTogXCJ0ZXN0LXBhY2thZ2VcIixcbiAgICAgICAgcmVzb3VyY2VzOiBbeyBuYW1lOiBcInRlc3RcIiwgZGF0YTogW10gfV0sXG4gICAgICB9XG4gICAgICBtb2NrTG9hZFBhY2thZ2VGcm9tQ2thbi5tb2NrUmVzb2x2ZWRWYWx1ZShtb2NrUGFja2FnZSlcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcGx1Z2luLmxvYWRQYWNrYWdlKFxuICAgICAgICBcImh0dHA6Ly9kYXRhLmV4YW1wbGUuY29tL2RhdGFzZXQvdGVzdC1kYXRhc2V0XCIsXG4gICAgICApXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tQ2thbikudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICAgIFwiaHR0cDovL2RhdGEuZXhhbXBsZS5jb20vZGF0YXNldC90ZXN0LWRhdGFzZXRcIixcbiAgICAgIClcbiAgICAgIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwobW9ja1BhY2thZ2UpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIHplbm9kbyB1cmxzXCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcImh0dHBzOi8vemVub2RvLm9yZy9yZWNvcmQvMTIzXCIpXG5cbiAgICAgIGV4cGVjdChtb2NrTG9hZFBhY2thZ2VGcm9tQ2thbikubm90LnRvSGF2ZUJlZW5DYWxsZWQoKVxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9CZVVuZGVmaW5lZCgpXG4gICAgfSlcblxuICAgIGl0KFwic2hvdWxkIHJldHVybiB1bmRlZmluZWQgZm9yIHVybHMgd2l0aCBkYXRhc2V0IGluIHF1ZXJ5IHBhcmFtcyBvbmx5XCIsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBsdWdpbi5sb2FkUGFja2FnZShcbiAgICAgICAgXCJodHRwczovL2V4YW1wbGUuY29tL2FwaT9uYW1lPWRhdGFzZXRcIixcbiAgICAgIClcblxuICAgICAgZXhwZWN0KG1vY2tMb2FkUGFja2FnZUZyb21Da2FuKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpXG4gICAgICBleHBlY3QocmVzdWx0KS50b0JlVW5kZWZpbmVkKClcbiAgICB9KVxuICB9KVxufSlcbiJdfQ==