@sumaris-net/ngx-components 18.26.13 → 18.26.14-alpha2

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 (71) hide show
  1. package/doc/changelog.md +44 -1
  2. package/esm2022/public_api.mjs +2 -1
  3. package/esm2022/src/app/admin/users/users.mjs +2 -2
  4. package/esm2022/src/app/core/about/about.modal.mjs +74 -13
  5. package/esm2022/src/app/core/account/account.page.mjs +1 -1
  6. package/esm2022/src/app/core/form/entity/entity-editor.class.mjs +2 -2
  7. package/esm2022/src/app/core/form/properties/properties.form.mjs +20 -3
  8. package/esm2022/src/app/core/form/properties/properties.table.mjs +3 -3
  9. package/esm2022/src/app/core/menu/menu.component.mjs +3 -3
  10. package/esm2022/src/app/core/register/register.form.mjs +1 -1
  11. package/esm2022/src/app/core/services/account.service.mjs +10 -5
  12. package/esm2022/src/app/core/services/config/core.config.mjs +6 -1
  13. package/esm2022/src/app/core/services/local-settings.service.mjs +3 -7
  14. package/esm2022/src/app/core/services/network.service.mjs +7 -1
  15. package/esm2022/src/app/core/services/platform.service.mjs +37 -7
  16. package/esm2022/src/app/core/settings/settings.page.mjs +55 -22
  17. package/esm2022/src/app/core/table/async-table.class.mjs +28 -15
  18. package/esm2022/src/app/core/table/column/row-field.component.mjs +8 -6
  19. package/esm2022/src/app/core/table/entities-async-table-datasource.class.mjs +1 -1
  20. package/esm2022/src/app/core/table/table.class.mjs +20 -14
  21. package/esm2022/src/app/shared/alerts.mjs +42 -8
  22. package/esm2022/src/app/shared/capacitor/plugins.mjs +2 -1
  23. package/esm2022/src/app/shared/form/field.component.mjs +7 -3
  24. package/esm2022/src/app/shared/gitlab/gitlab.utils.mjs +170 -0
  25. package/esm2022/src/app/shared/image/gallery/image-gallery.component.mjs +5 -5
  26. package/esm2022/src/app/shared/image/gallery/slideshow/image-gallery-slideshow.component.mjs +2 -2
  27. package/esm2022/src/app/shared/image/image.service.mjs +3 -3
  28. package/esm2022/src/app/shared/markdown/markdown.component.mjs +6 -5
  29. package/esm2022/src/app/shared/markdown/markdown.utils.mjs +3 -12
  30. package/esm2022/src/app/shared/markdown/testing/markdown.test.mjs +2 -2
  31. package/esm2022/src/app/shared/material/material.animations.mjs +7 -6
  32. package/esm2022/src/app/shared/material/paginator/material.paginator-i18n.mjs +25 -14
  33. package/esm2022/src/app/shared/platforms.mjs +23 -1
  34. package/esm2022/src/app/shared/upload-file/upload-file-popover.component.mjs +10 -4
  35. package/esm2022/src/app/shared/upload-file/upload-file.component.mjs +41 -4
  36. package/esm2022/src/app/shared/upload-file/upload-file.model.mjs +1 -1
  37. package/esm2022/src/app/shared/version/versions.mjs +10 -3
  38. package/esm2022/src/app/social/feed/feed.component.mjs +3 -3
  39. package/esm2022/src/environments/environment.class.mjs +2 -1
  40. package/esm2022/src/environments/environment.mjs +2 -1
  41. package/fesm2022/sumaris-net.ngx-components.mjs +595 -144
  42. package/fesm2022/sumaris-net.ngx-components.mjs.map +1 -1
  43. package/package.json +14 -13
  44. package/public_api.d.ts +1 -0
  45. package/src/app/core/about/about.modal.d.ts +9 -2
  46. package/src/app/core/form/entity/entity-editor.class.d.ts +4 -1
  47. package/src/app/core/form/properties/properties.form.d.ts +1 -0
  48. package/src/app/core/services/account.service.d.ts +1 -1
  49. package/src/app/core/services/config/core.config.d.ts +1 -0
  50. package/src/app/core/services/platform.service.d.ts +2 -0
  51. package/src/app/core/settings/settings.page.d.ts +2 -1
  52. package/src/app/core/table/async-table.class.d.ts +15 -3
  53. package/src/app/core/table/column/row-field.component.d.ts +3 -2
  54. package/src/app/core/table/table.class.d.ts +13 -3
  55. package/src/app/shared/alerts.d.ts +39 -4
  56. package/src/app/shared/capacitor/plugins.d.ts +1 -0
  57. package/src/app/shared/form/field.component.d.ts +2 -1
  58. package/src/app/shared/gitlab/gitlab.utils.d.ts +109 -0
  59. package/src/app/shared/image/gallery/image-gallery.component.d.ts +4 -0
  60. package/src/app/shared/markdown/markdown.utils.d.ts +0 -2
  61. package/src/app/shared/material/paginator/material.paginator-i18n.d.ts +5 -1
  62. package/src/app/shared/platforms.d.ts +1 -0
  63. package/src/app/shared/upload-file/upload-file-popover.component.d.ts +5 -1
  64. package/src/app/shared/upload-file/upload-file.component.d.ts +6 -2
  65. package/src/app/shared/upload-file/upload-file.model.d.ts +7 -0
  66. package/src/assets/i18n/en-US.json +4 -1
  67. package/src/assets/i18n/en.json +4 -1
  68. package/src/assets/i18n/fr.json +4 -1
  69. package/src/assets/manifest.json +1 -1
  70. package/src/environments/environment.class.d.ts +1 -0
  71. package/src/theme/_ngx-components.table.scss +5 -0
@@ -0,0 +1,170 @@
1
+ import { HttpUtils } from '../http/http.utils';
2
+ import { UrlUtils } from '../file/url.utils';
3
+ export class GitlabUtils {
4
+ static API_V4_PATH = '/api/v4/';
5
+ static API_V4_PROJECTS_PATH = '/api/v4/projects/';
6
+ /**
7
+ * Checks whether a URL points to a Gitlab instance.
8
+ *
9
+ * A URL is considered a Gitlab URL either when its host starts with 'gitlab.'
10
+ * (e.g. 'https://gitlab.ifremer.fr/...'), or when it is a repository file URL
11
+ * (see {@link isRepoFileUrl}) - in which case the host is NOT checked, since
12
+ * a self-hosted Gitlab instance may use a custom domain name.
13
+ *
14
+ * @example
15
+ * GitlabUtils.isGitlabUrl('https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app'); // true
16
+ * GitlabUtils.isGitlabUrl('https://my-custom-domain.com/foo/-/raw/master/README.md'); // true (repo file URL)
17
+ * GitlabUtils.isGitlabUrl('https://github.com/foo/bar'); // false
18
+ */
19
+ static isGitlabUrl(url) {
20
+ if (!url)
21
+ return false;
22
+ return url.startsWith('https://gitlab.') || GitlabUtils.isRepoFileUrl(url);
23
+ }
24
+ /**
25
+ * Checks whether a URL is a Gitlab repository file URL, i.e. a URL used to
26
+ * view a single file in a repository ('/-/blob/') or to download its raw
27
+ * content ('/-/raw/').
28
+ *
29
+ * @example
30
+ * GitlabUtils.isRepoFileUrl('https://gitlab.ifremer.fr/a/b/-/raw/master/README.md'); // true
31
+ * GitlabUtils.isRepoFileUrl('https://gitlab.ifremer.fr/a/b/-/blob/master/README.md'); // true
32
+ * GitlabUtils.isRepoFileUrl('https://gitlab.ifremer.fr/api/v4/projects/a%2Fb'); // false
33
+ */
34
+ static isRepoFileUrl(url) {
35
+ if (!url)
36
+ return false;
37
+ return url.includes('/-/raw/') || url.includes('/-/blob/');
38
+ }
39
+ /**
40
+ * Converts a repository file URL into its 'raw content' equivalent, by
41
+ * replacing the '/-/blob/' (file viewer) or '/-/tree/' (directory viewer)
42
+ * segment with '/-/raw/'.
43
+ *
44
+ * If the URL is not a repository file URL (see {@link isRepoFileUrl}), it is
45
+ * returned unchanged.
46
+ *
47
+ * @example
48
+ * GitlabUtils.getRawRepoFileUrl('https://gitlab.ifremer.fr/a/b/-/blob/master/README.md');
49
+ * // 'https://gitlab.ifremer.fr/a/b/-/raw/master/README.md'
50
+ */
51
+ static getRawRepoFileUrl(url) {
52
+ if (!GitlabUtils.isRepoFileUrl(url))
53
+ return url;
54
+ return url.replace('/-/blob/', '/-/raw/').replace('/-/tree/', '/-/raw/');
55
+ }
56
+ /**
57
+ * Checks whether a URL targets the Gitlab REST API (any endpoint under
58
+ * '/api/v4/'). Repository file URLs (see {@link isRepoFileUrl}) are always
59
+ * excluded, even if they happen to contain '/api/v4/' somewhere in their path.
60
+ */
61
+ static isApiUrl(url) {
62
+ if (!url || GitlabUtils.isRepoFileUrl(url))
63
+ return false;
64
+ return url.includes(GitlabUtils.API_V4_PATH);
65
+ }
66
+ /**
67
+ * Checks whether a URL targets the Gitlab 'projects' REST API (any endpoint
68
+ * under '/api/v4/projects/'), e.g. project releases, branches, etc.
69
+ */
70
+ static isApiProjectsUrl(url) {
71
+ if (!url || GitlabUtils.isRepoFileUrl(url))
72
+ return false;
73
+ return url.includes(GitlabUtils.API_V4_PROJECTS_PATH);
74
+ }
75
+ /**
76
+ * Checks whether a URL targets the Gitlab project releases REST API, e.g.
77
+ * 'https://gitlab.ifremer.fr/api/v4/projects/{id}/releases' (all releases)
78
+ * or 'https://gitlab.ifremer.fr/api/v4/projects/{id}/releases/{tag_name}'
79
+ * (a single release).
80
+ */
81
+ static isProjectReleasesApiUrl(url) {
82
+ return GitlabUtils.isApiProjectsUrl(url) && url.includes('/releases');
83
+ }
84
+ /**
85
+ * Fetches releases from the Gitlab project releases REST API.
86
+ *
87
+ * The given URL can either target the collection endpoint
88
+ * ('.../releases', returning all releases), or a single release endpoint
89
+ * ('.../releases/{tag_name}', returning one release, wrapped into an array).
90
+ *
91
+ * @return the list of releases, an empty array if the API call failed for a
92
+ * single release, or `null` if the URL is not a project releases API URL.
93
+ */
94
+ static async getProjectReleases(http, url) {
95
+ if (!GitlabUtils.isProjectReleasesApiUrl(url))
96
+ return null;
97
+ // Many releases API urls end with /releases
98
+ if (url.trim().endsWith('/releases')) {
99
+ return await HttpUtils.getJson(http, url);
100
+ }
101
+ // One release API url
102
+ try {
103
+ const release = await HttpUtils.getJson(http, url);
104
+ return release ? [release] : [];
105
+ }
106
+ catch (err) {
107
+ console.error('Failed to fetch release from the Gitlab API ' + url, err);
108
+ return null;
109
+ }
110
+ }
111
+ /**
112
+ * Extracts the URL-encoded project path (e.g. 'group%2Fsubgroup%2Fproject')
113
+ * from a Gitlab 'projects' API URL. The returned value is NOT decoded, so it
114
+ * still contains '%2F' in place of '/'.
115
+ *
116
+ * @example
117
+ * GitlabUtils.getProjectNameFromApiUrl('https://gitlab.ifremer.fr/api/v4/projects/sih-public%2Fsumaris%2Fsumaris-app/releases');
118
+ * // 'sih-public%2Fsumaris%2Fsumaris-app'
119
+ */
120
+ static getProjectNameFromApiUrl(url) {
121
+ if (!url?.includes(GitlabUtils.API_V4_PROJECTS_PATH))
122
+ return null;
123
+ return url.slice(url.indexOf(GitlabUtils.API_V4_PROJECTS_PATH) + GitlabUtils.API_V4_PROJECTS_PATH.length)
124
+ .split('/', 2)[0];
125
+ }
126
+ /**
127
+ * Resolves the Gitlab web page associated to a URL:
128
+ * - for an API 'projects' URL (see {@link isApiUrl}), this is the project's
129
+ * home page, e.g. 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app';
130
+ * - for a repository file URL (see {@link isRepoFileUrl}), this is the
131
+ * project's raw content base path (e.g. '.../my-project/-/raw/'), since
132
+ * the project path cannot be reliably distinguished from the file path
133
+ * once slashes are un-encoded.
134
+ *
135
+ * @return `null` if the project page cannot be resolved from the given URL.
136
+ */
137
+ static getProjectPage(url) {
138
+ if (GitlabUtils.isRepoFileUrl(url)) {
139
+ const fixUrl = GitlabUtils.getRawRepoFileUrl(url);
140
+ const index = fixUrl.indexOf('/-/raw/');
141
+ if (index >= 0)
142
+ return fixUrl.slice(0, index + '/-/raw/'.length);
143
+ }
144
+ else if (GitlabUtils.isApiUrl(url)) {
145
+ const index = url.indexOf(GitlabUtils.API_V4_PROJECTS_PATH);
146
+ if (index >= 0) {
147
+ const baseUrl = url.slice(0, index);
148
+ const projectName = GitlabUtils.getProjectNameFromApiUrl(url);
149
+ return UrlUtils.concat(baseUrl, projectName.replace(/%2F/g, '/'));
150
+ }
151
+ }
152
+ return null;
153
+ }
154
+ /**
155
+ * Builds the URL of the Gitlab web page listing a project's releases (e.g.
156
+ * 'https://gitlab.ifremer.fr/sih-public/sumaris/sumaris-app/-/releases'),
157
+ * optionally anchored on a specific version/tag.
158
+ *
159
+ * @param url any URL from which the project page can be resolved (see {@link getProjectPage})
160
+ * @param version optional tag name (e.g. '2.16.2') appended to the releases page
161
+ * @return `null` if the project page cannot be resolved from the given URL.
162
+ */
163
+ static getProjectReleasePage(url, version) {
164
+ const basePath = GitlabUtils.getProjectPage(url);
165
+ if (!basePath)
166
+ return null;
167
+ return UrlUtils.concat(UrlUtils.concat(basePath, '/-/releases'), version);
168
+ }
169
+ }
170
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0bGFiLnV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2FwcC9zaGFyZWQvZ2l0bGFiL2dpdGxhYi51dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sb0JBQW9CLENBQUM7QUFFN0MsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBUTdDLE1BQU0sT0FBTyxXQUFXO0lBQ3RCLE1BQU0sQ0FBQyxXQUFXLEdBQUcsVUFBVSxDQUFDO0lBQ2hDLE1BQU0sQ0FBQyxvQkFBb0IsR0FBRyxtQkFBbUIsQ0FBQztJQUVsRDs7Ozs7Ozs7Ozs7O09BWUc7SUFDSCxNQUFNLENBQUMsV0FBVyxDQUFDLEdBQVc7UUFDNUIsSUFBSSxDQUFDLEdBQUc7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUN2QixPQUFPLEdBQUcsQ0FBQyxVQUFVLENBQUMsaUJBQWlCLENBQUMsSUFBSSxXQUFXLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzdFLENBQUM7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSCxNQUFNLENBQUMsYUFBYSxDQUFDLEdBQVc7UUFDOUIsSUFBSSxDQUFDLEdBQUc7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUN2QixPQUFPLEdBQUcsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksR0FBRyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxNQUFNLENBQUMsaUJBQWlCLENBQUMsR0FBVztRQUNsQyxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUM7WUFBRSxPQUFPLEdBQUcsQ0FBQztRQUNoRCxPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLFNBQVMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsU0FBUyxDQUFD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QUMsRUFBRSxDQUFDO1lBQ3JDLE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDNUQsSUFBSSxLQUFLLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ2YsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7Z0JBQ3BDLE1BQU0sV0FBVyxHQUFHLFdBQVcsQ0FBQyx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDOUQsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1lBQ3BFLENBQUM7UUFDSCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxNQUFNLENBQUMscUJBQXFCLENBQUMsR0FBVyxFQUFFLE9BQWdCO1FBQ3hELE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLFFBQVE7WUFBRSxPQUFPLElBQUksQ0FBQztRQUUzQixPQUFPLFFBQVEsQ0FBQyxNQUFNLENBQ3BCLFFBQVEsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLGFBQWEsQ0FBQyxFQUN4QyxPQUFPLENBQ1IsQ0FBQztJQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0h0dHBVdGlsc30gZnJvbSAnLi4vaHR0cC9odHRwLnV0aWxzJztcbmltcG9ydCB7SHR0cENsaWVudH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgVXJsVXRpbHMgfSBmcm9tICcuLi9maWxlL3VybC51dGlscyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgSUdpdGxhYlJlbGVhc2Uge1xuICBuYW1lOiBzdHJpbmc7XG4gIHRhZ19uYW1lOiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uOiBzdHJpbmdcbn1cblxuZXhwb3J0IGNsYXNzIEdpdGxhYlV0aWxzIHtcbiAgc3RhdGljIEFQSV9WNF9QQVRIID0gJy9hcGkvdjQvJztcbiAgc3RhdGljIEFQSV9WNF9QUk9KRUNUU19QQVRIID0gJy9hcGkvdjQvcHJvamVjdHMvJztcblxuICAvKipcbiAgICogQ2hlY2tzIHdoZXRoZXIgYSBVUkwgcG9pbnRzIHRvIGEgR2l0bGFiIGluc3RhbmNlLlxuICAgKlxuICAgKiBBIFVSTCBpcyBjb25zaWRlcmVkIGEgR2l0bGFiIFVSTCBlaXRoZXIgd2hlbiBpdHMgaG9zdCBzdGFydHMgd2l0aCAnZ2l0bGFiLidcbiAgICogKGUuZy4gJ2h0dHBzOi8vZ2l0bGFiLmlmcmVtZXIuZnIvLi4uJyksIG9yIHdoZW4gaXQgaXMgYSByZXBvc2l0b3J5IGZpbGUgVVJMXG4gICAqIChzZWUge0BsaW5rIGlzUmVwb0ZpbGVVcmx9KSAtIGluIHdoaWNoIGNhc2UgdGhlIGhvc3QgaXMgTk9UIGNoZWNrZWQsIHNpbmNlXG4gICAqIGEgc2VsZi1ob3N0ZWQgR2l0bGFiIGluc3RhbmNlIG1heSB1c2UgYSBjdXN0b20gZG9tYWluIG5hbWUuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIEdpdGxhYlV0aWxzLmlzR2l0bGFiVXJsKCdodHRwczovL2dpdGxhYi5pZnJlbWVyLmZyL3NpaC1wdWJsaWMvc3VtYXJpcy9zdW1hcmlzLWFwcCcpOyAvLyB0cnVlXG4gICAqIEdpdGxhYlV0aWxzLmlzR2l0bGFiVXJsKCdodHRwczovL215LWN1c3RvbS1kb21haW4uY29tL2Zvby8tL3Jhdy9tYXN0ZXIvUkVBRE1FLm1kJyk7IC8vIHRydWUgKHJlcG8gZmlsZSBVUkwpXG4gICAqIEdpdGxhYlV0aWxzLmlzR2l0bGFiVXJsKCdodHRwczovL2dpdGh1Yi5jb20vZm9vL2JhcicpOyAvLyBmYWxzZVxuICAgKi9cbiAgc3RhdGljIGlzR2l0bGFiVXJsKHVybDogc3RyaW5nKSB7XG4gICAgaWYgKCF1cmwpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gdXJsLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vZ2l0bGFiLicpIHx8IEdpdGxhYlV0aWxzLmlzUmVwb0ZpbGVVcmwodXJsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciBhIFVSTCBpcyBhIEdpdGxhYiByZXBvc2l0b3J5IGZpbGUgVVJMLCBpLmUuIGEgVVJMIHVzZWQgdG9cbiAgICogdmlldyBhIHNpbmdsZSBmaWxlIGluIGEgcmVwb3NpdG9yeSAoJy8tL2Jsb2IvJykgb3IgdG8gZG93bmxvYWQgaXRzIHJhd1xuICAgKiBjb250ZW50ICgnLy0vcmF3LycpLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBHaXRsYWJVdGlscy5pc1JlcG9GaWxlVXJsKCdodHRwczovL2dpdGxhYi5pZnJlbWVyLmZyL2EvYi8tL3Jhdy9tYXN0ZXIvUkVBRE1FLm1kJyk7IC8vIHRydWVcbiAgICogR2l0bGFiVXRpbHMuaXNSZXBvRmlsZVVybCgnaHR0cHM6Ly9naXRsYWIuaWZyZW1lci5mci9hL2IvLS9ibG9iL21hc3Rlci9SRUFETUUubWQnKTsgLy8gdHJ1ZVxuICAgKiBHaXRsYWJVdGlscy5pc1JlcG9GaWxlVXJsKCdodHRwczovL2dpdGxhYi5pZnJlbWVyLmZyL2FwaS92NC9wcm9qZWN0cy9hJTJGYicpOyAvLyBmYWxzZVxuICAgKi9cbiAgc3RhdGljIGlzUmVwb0ZpbGVVcmwodXJsOiBzdHJpbmcpIHtcbiAgICBpZiAoIXVybCkgcmV0dXJuIGZhbHNlO1xuICAgIHJldHVybiB1cmwuaW5jbHVkZXMoJy8tL3Jhdy8nKSB8fCB1cmwuaW5jbHVkZXMoJy8tL2Jsb2IvJyk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSByZXBvc2l0b3J5IGZpbGUgVVJMIGludG8gaXRzICdyYXcgY29udGVudCcgZXF1aXZhbGVudCwgYnlcbiAgICogcmVwbGFjaW5nIHRoZSAnLy0vYmxvYi8nIChmaWxlIHZpZXdlcikgb3IgJy8tL3RyZWUvJyAoZGlyZWN0b3J5IHZpZXdlcilcbiAgICogc2VnbWVudCB3aXRoICcvLS9yYXcvJy5cbiAgICpcbiAgICogSWYgdGhlIFVSTCBpcyBub3QgYSByZXBvc2l0b3J5IGZpbGUgVVJMIChzZWUge0BsaW5rIGlzUmVwb0ZpbGVVcmx9KSwgaXQgaXNcbiAgICogcmV0dXJuZWQgdW5jaGFuZ2VkLlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBHaXRsYWJVdGlscy5nZXRSYXdSZXBvRmlsZVVybCgnaHR0cHM6Ly9naXRsYWIuaWZyZW1lci5mci9hL2IvLS9ibG9iL21hc3Rlci9SRUFETUUubWQnKTtcbiAgICogLy8gJ2h0dHBzOi8vZ2l0bGFiLmlmcmVtZXIuZnIvYS9iLy0vcmF3L21hc3Rlci9SRUFETUUubWQnXG4gICAqL1xuICBzdGF0aWMgZ2V0UmF3UmVwb0ZpbGVVcmwodXJsOiBzdHJpbmcpIHtcbiAgICBpZiAoIUdpdGxhYlV0aWxzLmlzUmVwb0ZpbGVVcmwodXJsKSkgcmV0dXJuIHVybDtcbiAgICByZXR1cm4gdXJsLnJlcGxhY2UoJy8tL2Jsb2IvJywgJy8tL3Jhdy8nKS5yZXBsYWNlKCcvLS90cmVlLycsICcvLS9yYXcvJyk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIHdoZXRoZXIgYSBVUkwgdGFyZ2V0cyB0aGUgR2l0bGFiIFJFU1QgQVBJIChhbnkgZW5kcG9pbnQgdW5kZXJcbiAgICogJy9hcGkvdjQvJykuIFJlcG9zaXRvcnkgZmlsZSBVUkxzIChzZWUge0BsaW5rIGlzUmVwb0ZpbGVVcmx9KSBhcmUgYWx3YXlzXG4gICAqIGV4Y2x1ZGVkLCBldmVuIGlmIHRoZXkgaGFwcGVuIHRvIGNvbnRhaW4gJy9hcGkvdjQvJyBzb21ld2hlcmUgaW4gdGhlaXIgcGF0aC5cbiAgICovXG4gIHN0YXRpYyBpc0FwaVVybCh1cmw6IHN0cmluZykge1xuICAgIGlmICghdXJsIHx8IEdpdGxhYlV0aWxzLmlzUmVwb0ZpbGVVcmwodXJsKSkgcmV0dXJuIGZhbHNlO1xuICAgIHJldHVybiB1cmwuaW5jbHVkZXMoR2l0bGFiVXRpbHMuQVBJX1Y0X1BBVEgpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyB3aGV0aGVyIGEgVVJMIHRhcmdldHMgdGhlIEdpdGxhYiAncHJvamVjdHMnIFJFU1QgQVBJIChhbnkgZW5kcG9pbnRcbiAgICogdW5kZXIgJy9hcGkvdjQvcHJvamVjdHMvJyksIGUuZy4gcHJvamVjdCByZWxlYXNlcywgYnJhbmNoZXMsIGV0Yy5cbiAgICovXG4gIHN0YXRpYyBpc0FwaVByb2plY3RzVXJsKHVybDogc3RyaW5nKSB7XG4gICAgaWYgKCF1cmwgfHwgR2l0bGFiVXRpbHMuaXNSZXBvRmlsZVVybCh1cmwpKSByZXR1cm4gZmFsc2U7XG4gICAgcmV0dXJuIHVybC5pbmNsdWRlcyhHaXRsYWJVdGlscy5BUElfVjRfUFJPSkVDVFNfUEFUSCk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIHdoZXRoZXIgYSBVUkwgdGFyZ2V0cyB0aGUgR2l0bGFiIHByb2plY3QgcmVsZWFzZXMgUkVTVCBBUEksIGUuZy5cbiAgICogJ2h0dHBzOi8vZ2l0bGFiLmlmcmVtZXIuZnIvYXBpL3Y0L3Byb2plY3RzL3tpZH0vcmVsZWFzZXMnIChhbGwgcmVsZWFzZXMpXG4gICAqIG9yICdodHRwczovL2dpdGxhYi5pZnJlbWVyLmZyL2FwaS92NC9wcm9qZWN0cy97aWR9L3JlbGVhc2VzL3t0YWdfbmFtZX0nXG4gICAqIChhIHNpbmdsZSByZWxlYXNlKS5cbiAgICovXG4gIHN0YXRpYyBpc1Byb2plY3RSZWxlYXNlc0FwaVVybCh1cmw6IHN0cmluZykge1xuICAgIHJldHVybiBHaXRsYWJVdGlscy5pc0FwaVByb2plY3RzVXJsKHVybCkgJiYgdXJsLmluY2x1ZGVzKCcvcmVsZWFzZXMnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaGVzIHJlbGVhc2VzIGZyb20gdGhlIEdpdGxhYiBwcm9qZWN0IHJlbGVhc2VzIFJFU1QgQVBJLlxuICAgKlxuICAgKiBUaGUgZ2l2ZW4gVVJMIGNhbiBlaXRoZXIgdGFyZ2V0IHRoZSBjb2xsZWN0aW9uIGVuZHBvaW50XG4gICAqICgnLi4uL3JlbGVhc2VzJywgcmV0dXJuaW5nIGFsbCByZWxlYXNlcyksIG9yIGEgc2luZ2xlIHJlbGVhc2UgZW5kcG9pbnRcbiAgICogKCcuLi4vcmVsZWFzZXMve3RhZ19uYW1lfScsIHJldHVybmluZyBvbmUgcmVsZWFzZSwgd3JhcHBlZCBpbnRvIGFuIGFycmF5KS5cbiAgICpcbiAgICogQHJldHVybiB0aGUgbGlzdCBvZiByZWxlYXNlcywgYW4gZW1wdHkgYXJyYXkgaWYgdGhlIEFQSSBjYWxsIGZhaWxlZCBmb3IgYVxuICAgKiAgIHNpbmdsZSByZWxlYXNlLCBvciBgbnVsbGAgaWYgdGhlIFVSTCBpcyBub3QgYSBwcm9qZWN0IHJlbGVhc2VzIEFQSSBVUkwuXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0UHJvamVjdFJlbGVhc2VzKGh0dHA6IEh0dHBDbGllbnQsIHVybDogc3RyaW5nKSB7XG4gICAgaWYgKCFHaXRsYWJVdGlscy5pc1Byb2plY3RSZWxlYXNlc0FwaVVybCh1cmwpKSByZXR1cm4gbnVsbDtcblxuICAgIC8vIE1hbnkgcmVsZWFzZXMgQVBJIHVybHMgZW5kIHdpdGggL3JlbGVhc2VzXG4gICAgaWYgKHVybC50cmltKCkuZW5kc1dpdGgoJy9yZWxlYXNlcycpKSB7XG4gICAgICByZXR1cm4gYXdhaXQgSHR0cFV0aWxzLmdldEpzb248SUdpdGxhYlJlbGVhc2VbXT4oaHR0cCwgdXJsKTtcbiAgICB9XG5cbiAgICAvLyBPbmUgcmVsZWFzZSBBUEkgdXJsXG4gICAgdHJ5IHtcbiAgICBjb25zdCByZWxlYXNlID0gYXdhaXQgSHR0cFV0aWxzLmdldEpzb248SUdpdGxhYlJlbGVhc2U+KGh0dHAsIHVybCk7XG4gICAgcmV0dXJuIHJlbGVhc2UgPyBbcmVsZWFzZV0gOiBbXTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ0ZhaWxlZCB0byBmZXRjaCByZWxlYXNlIGZyb20gdGhlIEdpdGxhYiBBUEkgJyArIHVybCwgZXJyKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0cyB0aGUgVVJMLWVuY29kZWQgcHJvamVjdCBwYXRoIChlLmcuICdncm91cCUyRnN1Ymdyb3VwJTJGcHJvamVjdCcpXG4gICAqIGZyb20gYSBHaXRsYWIgJ3Byb2plY3RzJyBBUEkgVVJMLiBUaGUgcmV0dXJuZWQgdmFsdWUgaXMgTk9UIGRlY29kZWQsIHNvIGl0XG4gICAqIHN0aWxsIGNvbnRhaW5zICclMkYnIGluIHBsYWNlIG9mICcvJy5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogR2l0bGFiVXRpbHMuZ2V0UHJvamVjdE5hbWVGcm9tQXBpVXJsKCdodHRwczovL2dpdGxhYi5pZnJlbWVyLmZyL2FwaS92NC9wcm9qZWN0cy9zaWgtcHVibGljJTJGc3VtYXJpcyUyRnN1bWFyaXMtYXBwL3JlbGVhc2VzJyk7XG4gICAqIC8vICdzaWgtcHVibGljJTJGc3VtYXJpcyUyRnN1bWFyaXMtYXBwJ1xuICAgKi9cbiAgc3RhdGljIGdldFByb2plY3ROYW1lRnJvbUFwaVVybCh1cmw6IHN0cmluZykge1xuICAgIGlmICghdXJsPy5pbmNsdWRlcyhHaXRsYWJVdGlscy5BUElfVjRfUFJPSkVDVFNfUEFUSCkpIHJldHVybiBudWxsO1xuXG4gICAgcmV0dXJuIHVybC5zbGljZSh1cmwuaW5kZXhPZihHaXRsYWJVdGlscy5BUElfVjRfUFJPSkVDVFNfUEFUSCkgKyBHaXRsYWJVdGlscy5BUElfVjRfUFJPSkVDVFNfUEFUSC5sZW5ndGgpXG4gICAgICAuc3BsaXQoJy8nLCAyKVswXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlcyB0aGUgR2l0bGFiIHdlYiBwYWdlIGFzc29jaWF0ZWQgdG8gYSBVUkw6XG4gICAqIC0gZm9yIGFuIEFQSSAncHJvamVjdHMnIFVSTCAoc2VlIHtAbGluayBpc0FwaVVybH0pLCB0aGlzIGlzIHRoZSBwcm9qZWN0J3NcbiAgICogICBob21lIHBhZ2UsIGUuZy4gJ2h0dHBzOi8vZ2l0bGFiLmlmcmVtZXIuZnIvc2loLXB1YmxpYy9zdW1hcmlzL3N1bWFyaXMtYXBwJztcbiAgICogLSBmb3IgYSByZXBvc2l0b3J5IGZpbGUgVVJMIChzZWUge0BsaW5rIGlzUmVwb0ZpbGVVcmx9KSwgdGhpcyBpcyB0aGVcbiAgICogICBwcm9qZWN0J3MgcmF3IGNvbnRlbnQgYmFzZSBwYXRoIChlLmcuICcuLi4vbXktcHJvamVjdC8tL3Jhdy8nKSwgc2luY2VcbiAgICogICB0aGUgcHJvamVjdCBwYXRoIGNhbm5vdCBiZSByZWxpYWJseSBkaXN0aW5ndWlzaGVkIGZyb20gdGhlIGZpbGUgcGF0aFxuICAgKiAgIG9uY2Ugc2xhc2hlcyBhcmUgdW4tZW5jb2RlZC5cbiAgICpcbiAgICogQHJldHVybiBgbnVsbGAgaWYgdGhlIHByb2plY3QgcGFnZSBjYW5ub3QgYmUgcmVzb2x2ZWQgZnJvbSB0aGUgZ2l2ZW4gVVJMLlxuICAgKi9cbiAgc3RhdGljIGdldFByb2plY3RQYWdlKHVybDogc3RyaW5nKSB7XG4gICAgaWYgKEdpdGxhYlV0aWxzLmlzUmVwb0ZpbGVVcmwodXJsKSkge1xuICAgICAgY29uc3QgZml4VXJsID0gR2l0bGFiVXRpbHMuZ2V0UmF3UmVwb0ZpbGVVcmwodXJsKTtcbiAgICAgIGNvbnN0IGluZGV4ID0gZml4VXJsLmluZGV4T2YoJy8tL3Jhdy8nKTtcbiAgICAgIGlmIChpbmRleCA+PSAwKSByZXR1cm4gZml4VXJsLnNsaWNlKDAsIGluZGV4ICsgJy8tL3Jhdy8nLmxlbmd0aCk7XG4gICAgfSBlbHNlIGlmIChHaXRsYWJVdGlscy5pc0FwaVVybCh1cmwpKSB7XG4gICAgICBjb25zdCBpbmRleCA9IHVybC5pbmRleE9mKEdpdGxhYlV0aWxzLkFQSV9WNF9QUk9KRUNUU19QQVRIKTtcbiAgICAgIGlmIChpbmRleCA+PSAwKSB7XG4gICAgICAgIGNvbnN0IGJhc2VVcmwgPSB1cmwuc2xpY2UoMCwgaW5kZXgpO1xuICAgICAgICBjb25zdCBwcm9qZWN0TmFtZSA9IEdpdGxhYlV0aWxzLmdldFByb2plY3ROYW1lRnJvbUFwaVVybCh1cmwpO1xuICAgICAgICByZXR1cm4gVXJsVXRpbHMuY29uY2F0KGJhc2VVcmwsIHByb2plY3ROYW1lLnJlcGxhY2UoLyUyRi9nLCAnLycpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgdGhlIFVSTCBvZiB0aGUgR2l0bGFiIHdlYiBwYWdlIGxpc3RpbmcgYSBwcm9qZWN0J3MgcmVsZWFzZXMgKGUuZy5cbiAgICogJ2h0dHBzOi8vZ2l0bGFiLmlmcmVtZXIuZnIvc2loLXB1YmxpYy9zdW1hcmlzL3N1bWFyaXMtYXBwLy0vcmVsZWFzZXMnKSxcbiAgICogb3B0aW9uYWxseSBhbmNob3JlZCBvbiBhIHNwZWNpZmljIHZlcnNpb24vdGFnLlxuICAgKlxuICAgKiBAcGFyYW0gdXJsIGFueSBVUkwgZnJvbSB3aGljaCB0aGUgcHJvamVjdCBwYWdlIGNhbiBiZSByZXNvbHZlZCAoc2VlIHtAbGluayBnZXRQcm9qZWN0UGFnZX0pXG4gICAqIEBwYXJhbSB2ZXJzaW9uIG9wdGlvbmFsIHRhZyBuYW1lIChlLmcuICcyLjE2LjInKSBhcHBlbmRlZCB0byB0aGUgcmVsZWFzZXMgcGFnZVxuICAgKiBAcmV0dXJuIGBudWxsYCBpZiB0aGUgcHJvamVjdCBwYWdlIGNhbm5vdCBiZSByZXNvbHZlZCBmcm9tIHRoZSBnaXZlbiBVUkwuXG4gICAqL1xuICBzdGF0aWMgZ2V0UHJvamVjdFJlbGVhc2VQYWdlKHVybDogc3RyaW5nLCB2ZXJzaW9uPzogc3RyaW5nKSB7XG4gICAgY29uc3QgYmFzZVBhdGggPSBHaXRsYWJVdGlscy5nZXRQcm9qZWN0UGFnZSh1cmwpO1xuICAgIGlmICghYmFzZVBhdGgpIHJldHVybiBudWxsO1xuXG4gICAgcmV0dXJuIFVybFV0aWxzLmNvbmNhdChcbiAgICAgIFVybFV0aWxzLmNvbmNhdChiYXNlUGF0aCwgJy8tL3JlbGVhc2VzJyksXG4gICAgICB2ZXJzaW9uXG4gICAgKTtcbiAgfVxufVxuIl19