@electron-forge/publisher-bitbucket 6.0.0 → 6.0.2

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.
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2016 Samuel Attard
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ the Software, and to permit persons to whom the Software is furnished to do so,
9
+ subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electron-forge/publisher-bitbucket",
3
- "version": "6.0.0",
3
+ "version": "6.0.2",
4
4
  "description": "Bitbucket publisher for Electron Forge",
5
5
  "repository": "https://github.com/electron/forge",
6
6
  "author": "Luke Batchelor",
@@ -15,10 +15,13 @@
15
15
  "node": ">= 14.17.5"
16
16
  },
17
17
  "dependencies": {
18
- "@electron-forge/async-ora": "6.0.0",
19
- "@electron-forge/publisher-base": "6.0.0",
18
+ "@electron-forge/publisher-base": "^6.0.2",
20
19
  "form-data": "^4.0.0",
21
20
  "fs-extra": "^10.0.0",
22
21
  "node-fetch": "^2.6.7"
23
- }
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "gitHead": "11cf4b58359c9881c05c06e0d62be575a0ed70d1"
24
27
  }
package/src/Config.ts ADDED
@@ -0,0 +1,44 @@
1
+ export interface BitbucketRepository {
2
+ /**
3
+ * The name of your repository
4
+ */
5
+ name: string;
6
+ /**
7
+ * The owner of your repository, this is either your username or the name of
8
+ * the organization that owns the repository.
9
+ */
10
+ owner: string;
11
+ }
12
+
13
+ export interface BitbucketAuth {
14
+ /**
15
+ * The username to use when uploading.
16
+ *
17
+ * You can set the BITBUCKET_USERNAME environment variable if you don't want to hard
18
+ * code this into your config.
19
+ */
20
+ username?: string;
21
+ /**
22
+ * An authorization token with permission to upload downloads to this
23
+ * repository.
24
+ *
25
+ * You can set the BITBUCKET_APP_PASSWORD environment variable if you don't want to hard
26
+ * code this into your config.
27
+ */
28
+ appPassword?: string;
29
+ }
30
+
31
+ export interface PublisherBitbucketConfig {
32
+ /**
33
+ * Details that identify your repository (name and owner)
34
+ */
35
+ repository: BitbucketRepository;
36
+ /**
37
+ * User details for uploading releases
38
+ */
39
+ auth: BitbucketAuth;
40
+ /**
41
+ * If true, will replace an existing files of the same name (will throw an error otherwise).
42
+ */
43
+ replaceExistingFiles?: boolean;
44
+ }
@@ -0,0 +1,83 @@
1
+ import path from 'path';
2
+
3
+ import { PublisherBase, PublisherOptions } from '@electron-forge/publisher-base';
4
+ import FormData from 'form-data';
5
+ import fs from 'fs-extra';
6
+ import fetch from 'node-fetch';
7
+
8
+ import { PublisherBitbucketConfig } from './Config';
9
+
10
+ export default class PublisherBitbucket extends PublisherBase<PublisherBitbucketConfig> {
11
+ name = 'bitbucket';
12
+
13
+ async publish({ makeResults, setStatusLine }: PublisherOptions): Promise<void> {
14
+ const { config } = this;
15
+ const hasRepositoryConfig = config.repository && typeof config.repository;
16
+ const replaceExistingFiles = Boolean(config.replaceExistingFiles);
17
+ const appPassword = process.env.BITBUCKET_APP_PASSWORD;
18
+ const username = process.env.BITBUCKET_USERNAME;
19
+ const auth = { appPassword, username, ...(config.auth || {}) };
20
+ const apiUrl = `https://api.bitbucket.org/2.0/repositories/${config.repository.owner}/${config.repository.name}/downloads`;
21
+ const encodedUserAndPass = Buffer.from(`${auth.username}:${auth.appPassword}`).toString('base64');
22
+
23
+ if (!(hasRepositoryConfig && config.repository.owner && config.repository.name)) {
24
+ throw new Error(
25
+ 'In order to publish to Bitbucket you must set the "repository.owner" and "repository.name" properties in your Forge config. See the docs for more info'
26
+ );
27
+ }
28
+
29
+ if (!auth.appPassword || !auth.username) {
30
+ throw new Error(
31
+ 'In order to publish to Bitbucket provide credentials, either through "auth.appPassword" and "auth.username" properties in your Forge config or using BITBUCKET_APP_PASSWORD and BITBUCKET_USERNAME environment variables'
32
+ );
33
+ }
34
+
35
+ for (const [index, makeResult] of makeResults.entries()) {
36
+ const data = new FormData();
37
+
38
+ for (const artifactPath of makeResult.artifacts) {
39
+ data.append('files', fs.createReadStream(artifactPath));
40
+ }
41
+
42
+ // If we are not supposed to override an existing version, we'll check check if any of
43
+ // the files exist first
44
+ if (!replaceExistingFiles) {
45
+ for (const artifactPath of makeResult.artifacts) {
46
+ const fileName = path.basename(artifactPath);
47
+
48
+ const response = await fetch(`${apiUrl}/${fileName}`, {
49
+ headers: {
50
+ Authorization: `Basic ${encodedUserAndPass}`,
51
+ },
52
+ method: 'HEAD',
53
+ // We set redirect to 'manual' so that we get the 302 redirects if the file
54
+ // already exists
55
+ redirect: 'manual',
56
+ });
57
+
58
+ if (response.status === 302) {
59
+ throw new Error(
60
+ `Unable to publish "${fileName}" as it has been published previously. Use the "replaceExistingFiles" property in your Forge config to override this.`
61
+ );
62
+ }
63
+ }
64
+ }
65
+
66
+ setStatusLine(`Uploading distributable (${index + 1}/${makeResults.length})`);
67
+ const response = await fetch(apiUrl, {
68
+ headers: {
69
+ Authorization: `Basic ${encodedUserAndPass}`,
70
+ },
71
+ method: 'POST',
72
+ body: data,
73
+ });
74
+
75
+ // We will get a 200 on the inital upload and a 201 if publishing over the same version
76
+ if (response.status !== 200 && response.status !== 201) {
77
+ throw new Error(`Unexpected response code from Bitbucket: ${response.status} ${response.statusText}\n\nBody:\n${await response.text()}`);
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ export { PublisherBitbucket, PublisherBitbucketConfig };
package/tsconfig.json CHANGED
@@ -29,9 +29,6 @@
29
29
  "tmpl"
30
30
  ],
31
31
  "references": [
32
- {
33
- "path": "../../utils/async-ora"
34
- },
35
32
  {
36
33
  "path": "../base"
37
34
  }
package/dist/Config.d.ts DELETED
@@ -1,43 +0,0 @@
1
- export interface BitbucketRepository {
2
- /**
3
- * The name of your repository
4
- */
5
- name: string;
6
- /**
7
- * The owner of your repository, this is either your username or the name of
8
- * the organization that owns the repository.
9
- */
10
- owner: string;
11
- }
12
- export interface BitbucketAuth {
13
- /**
14
- * The username to use when uploading.
15
- *
16
- * You can set the BITBUCKET_USERNAME environment variable if you don't want to hard
17
- * code this into your config.
18
- */
19
- username?: string;
20
- /**
21
- * An authorization token with permission to upload downloads to this
22
- * repository.
23
- *
24
- * You can set the BITBUCKET_APP_PASSWORD environment variable if you don't want to hard
25
- * code this into your config.
26
- */
27
- appPassword?: string;
28
- }
29
- export interface PublisherBitbucketConfig {
30
- /**
31
- * Details that identify your repository (name and owner)
32
- */
33
- repository: BitbucketRepository;
34
- /**
35
- * User details for uploading releases
36
- */
37
- auth: BitbucketAuth;
38
- /**
39
- * If true, will replace an existing files of the same name (will throw an error otherwise).
40
- */
41
- replaceExistingFiles?: boolean;
42
- }
43
- //# sourceMappingURL=Config.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../src/Config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,UAAU,EAAE,mBAAmB,CAAC;IAChC;;OAEG;IACH,IAAI,EAAE,aAAa,CAAC;IACpB;;OAEG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC"}
package/dist/Config.js DELETED
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
-
6
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
@@ -1,8 +0,0 @@
1
- import { PublisherBase, PublisherOptions } from '@electron-forge/publisher-base';
2
- import { PublisherBitbucketConfig } from './Config';
3
- export default class PublisherBitbucket extends PublisherBase<PublisherBitbucketConfig> {
4
- name: string;
5
- publish({ makeResults }: PublisherOptions): Promise<void>;
6
- }
7
- export { PublisherBitbucket, PublisherBitbucketConfig };
8
- //# sourceMappingURL=PublisherBitbucket.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PublisherBitbucket.d.ts","sourceRoot":"","sources":["../src/PublisherBitbucket.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAKjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,aAAa,CAAC,wBAAwB,CAAC;IACrF,IAAI,SAAe;IAEb,OAAO,CAAC,EAAE,WAAW,EAAE,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;CAuEhE;AAED,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,CAAC"}
@@ -1,93 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "PublisherBitbucketConfig", {
6
- enumerable: true,
7
- get: function() {
8
- return _config.PublisherBitbucketConfig;
9
- }
10
- });
11
- exports.PublisherBitbucket = exports.default = void 0;
12
- var _path = _interopRequireDefault(require("path"));
13
- var _asyncOra = require("@electron-forge/async-ora");
14
- var _publisherBase = require("@electron-forge/publisher-base");
15
- var _formData = _interopRequireDefault(require("form-data"));
16
- var _fsExtra = _interopRequireDefault(require("fs-extra"));
17
- var _nodeFetch = _interopRequireDefault(require("node-fetch"));
18
- var _config = require("./Config");
19
- function _interopRequireDefault(obj) {
20
- return obj && obj.__esModule ? obj : {
21
- default: obj
22
- };
23
- }
24
- class PublisherBitbucket extends _publisherBase.PublisherBase {
25
- async publish({ makeResults }) {
26
- const { config } = this;
27
- const hasRepositoryConfig = config.repository && typeof config.repository;
28
- const replaceExistingFiles = Boolean(config.replaceExistingFiles);
29
- const appPassword = process.env.BITBUCKET_APP_PASSWORD;
30
- const username = process.env.BITBUCKET_USERNAME;
31
- const auth = {
32
- appPassword,
33
- username,
34
- ...config.auth || {}
35
- };
36
- const apiUrl = `https://api.bitbucket.org/2.0/repositories/${config.repository.owner}/${config.repository.name}/downloads`;
37
- const encodedUserAndPass = Buffer.from(`${auth.username}:${auth.appPassword}`).toString('base64');
38
- if (!(hasRepositoryConfig && config.repository.owner && config.repository.name)) {
39
- throw new Error('In order to publish to Bitbucket you must set the "repository.owner" and "repository.name" properties in your Forge config. See the docs for more info');
40
- }
41
- if (!auth.appPassword || !auth.username) {
42
- throw new Error('In order to publish to Bitbucket provide credentials, either through "auth.appPassword" and "auth.username" properties in your Forge config or using BITBUCKET_APP_PASSWORD and BITBUCKET_USERNAME environment variables');
43
- }
44
- for (const [index, makeResult] of makeResults.entries()){
45
- const data = new _formData.default();
46
- for (const artifactPath1 of makeResult.artifacts){
47
- data.append('files', _fsExtra.default.createReadStream(artifactPath1));
48
- }
49
- // If we are not supposed to override an existing version, we'll check check if any of
50
- // the files exist first
51
- if (!replaceExistingFiles) {
52
- await (0, _asyncOra).asyncOra('Checking if artifacts have been published previously', async ()=>{
53
- for (const artifactPath of makeResult.artifacts){
54
- const fileName = _path.default.basename(artifactPath);
55
- const response = await (0, _nodeFetch).default(`${apiUrl}/${fileName}`, {
56
- headers: {
57
- Authorization: `Basic ${encodedUserAndPass}`
58
- },
59
- method: 'HEAD',
60
- // We set redirect to 'manual' so that we get the 302 redirects if the file
61
- // already exists
62
- redirect: 'manual'
63
- });
64
- if (response.status === 302) {
65
- throw new Error(`Unable to publish "${fileName}" as it has been published previously. Use the "replaceExistingFiles" property in your Forge config to override this.`);
66
- }
67
- }
68
- });
69
- }
70
- await (0, _asyncOra).asyncOra(`Uploading result (${index + 1}/${makeResults.length})`, async ()=>{
71
- const response = await (0, _nodeFetch).default(apiUrl, {
72
- headers: {
73
- Authorization: `Basic ${encodedUserAndPass}`
74
- },
75
- method: 'POST',
76
- body: data
77
- });
78
- // We will get a 200 on the inital upload and a 201 if publishing over the same version
79
- if (response.status !== 200 && response.status !== 201) {
80
- throw new Error(`Unexpected response code from Bitbucket: ${response.status} ${response.statusText}\n\nBody:\n${await response.text()}`);
81
- }
82
- });
83
- }
84
- }
85
- constructor(...args){
86
- super(...args);
87
- this.name = 'bitbucket';
88
- }
89
- }
90
- exports.default = PublisherBitbucket;
91
- exports.PublisherBitbucket = PublisherBitbucket;
92
-
93
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9QdWJsaXNoZXJCaXRidWNrZXQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7IGFzeW5jT3JhIH0gZnJvbSAnQGVsZWN0cm9uLWZvcmdlL2FzeW5jLW9yYSc7XG5pbXBvcnQgeyBQdWJsaXNoZXJCYXNlLCBQdWJsaXNoZXJPcHRpb25zIH0gZnJvbSAnQGVsZWN0cm9uLWZvcmdlL3B1Ymxpc2hlci1iYXNlJztcbmltcG9ydCBGb3JtRGF0YSBmcm9tICdmb3JtLWRhdGEnO1xuaW1wb3J0IGZzIGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCBmZXRjaCBmcm9tICdub2RlLWZldGNoJztcblxuaW1wb3J0IHsgUHVibGlzaGVyQml0YnVja2V0Q29uZmlnIH0gZnJvbSAnLi9Db25maWcnO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBQdWJsaXNoZXJCaXRidWNrZXQgZXh0ZW5kcyBQdWJsaXNoZXJCYXNlPFB1Ymxpc2hlckJpdGJ1Y2tldENvbmZpZz4ge1xuICBuYW1lID0gJ2JpdGJ1Y2tldCc7XG5cbiAgYXN5bmMgcHVibGlzaCh7IG1ha2VSZXN1bHRzIH06IFB1Ymxpc2hlck9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGNvbmZpZyB9ID0gdGhpcztcbiAgICBjb25zdCBoYXNSZXBvc2l0b3J5Q29uZmlnID0gY29uZmlnLnJlcG9zaXRvcnkgJiYgdHlwZW9mIGNvbmZpZy5yZXBvc2l0b3J5O1xuICAgIGNvbnN0IHJlcGxhY2VFeGlzdGluZ0ZpbGVzID0gQm9vbGVhbihjb25maWcucmVwbGFjZUV4aXN0aW5nRmlsZXMpO1xuICAgIGNvbnN0IGFwcFBhc3N3b3JkID0gcHJvY2Vzcy5lbnYuQklUQlVDS0VUX0FQUF9QQVNTV09SRDtcbiAgICBjb25zdCB1c2VybmFtZSA9IHByb2Nlc3MuZW52LkJJVEJVQ0tFVF9VU0VSTkFNRTtcbiAgICBjb25zdCBhdXRoID0geyBhcHBQYXNzd29yZCwgdXNlcm5hbWUsIC4uLihjb25maWcuYXV0aCB8fCB7fSkgfTtcbiAgICBjb25zdCBhcGlVcmwgPSBgaHR0cHM6Ly9hcGkuYml0YnVja2V0Lm9yZy8yLjAvcmVwb3NpdG9yaWVzLyR7Y29uZmlnLnJlcG9zaXRvcnkub3duZXJ9LyR7Y29uZmlnLnJlcG9zaXRvcnkubmFtZX0vZG93bmxvYWRzYDtcbiAgICBjb25zdCBlbmNvZGVkVXNlckFuZFBhc3MgPSBCdWZmZXIuZnJvbShgJHthdXRoLnVzZXJuYW1lfToke2F1dGguYXBwUGFzc3dvcmR9YCkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuXG4gICAgaWYgKCEoaGFzUmVwb3NpdG9yeUNvbmZpZyAmJiBjb25maWcucmVwb3NpdG9yeS5vd25lciAmJiBjb25maWcucmVwb3NpdG9yeS5uYW1lKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnSW4gb3JkZXIgdG8gcHVibGlzaCB0byBCaXRidWNrZXQgeW91IG11c3Qgc2V0IHRoZSBcInJlcG9zaXRvcnkub3duZXJcIiBhbmQgXCJyZXBvc2l0b3J5Lm5hbWVcIiBwcm9wZXJ0aWVzIGluIHlvdXIgRm9yZ2UgY29uZmlnLiBTZWUgdGhlIGRvY3MgZm9yIG1vcmUgaW5mbydcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFhdXRoLmFwcFBhc3N3b3JkIHx8ICFhdXRoLnVzZXJuYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdJbiBvcmRlciB0byBwdWJsaXNoIHRvIEJpdGJ1Y2tldCBwcm92aWRlIGNyZWRlbnRpYWxzLCBlaXRoZXIgdGhyb3VnaCBcImF1dGguYXBwUGFzc3dvcmRcIiBhbmQgXCJhdXRoLnVzZXJuYW1lXCIgcHJvcGVydGllcyBpbiB5b3VyIEZvcmdlIGNvbmZpZyBvciB1c2luZyBCSVRCVUNLRVRfQVBQX1BBU1NXT1JEIGFuZCBCSVRCVUNLRVRfVVNFUk5BTUUgZW52aXJvbm1lbnQgdmFyaWFibGVzJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtpbmRleCwgbWFrZVJlc3VsdF0gb2YgbWFrZVJlc3VsdHMuZW50cmllcygpKSB7XG4gICAgICBjb25zdCBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG5cbiAgICAgIGZvciAoY29uc3QgYXJ0aWZhY3RQYXRoIG9mIG1ha2VSZXN1bHQuYXJ0aWZhY3RzKSB7XG4gICAgICAgIGRhdGEuYXBwZW5kKCdmaWxlcycsIGZzLmNyZWF0ZVJlYWRTdHJlYW0oYXJ0aWZhY3RQYXRoKSk7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIHdlIGFyZSBub3Qgc3VwcG9zZWQgdG8gb3ZlcnJpZGUgYW4gZXhpc3RpbmcgdmVyc2lvbiwgd2UnbGwgY2hlY2sgY2hlY2sgaWYgYW55IG9mXG4gICAgICAvLyB0aGUgZmlsZXMgZXhpc3QgZmlyc3RcbiAgICAgIGlmICghcmVwbGFjZUV4aXN0aW5nRmlsZXMpIHtcbiAgICAgICAgYXdhaXQgYXN5bmNPcmEoJ0NoZWNraW5nIGlmIGFydGlmYWN0cyBoYXZlIGJlZW4gcHVibGlzaGVkIHByZXZpb3VzbHknLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgZm9yIChjb25zdCBhcnRpZmFjdFBhdGggb2YgbWFrZVJlc3VsdC5hcnRpZmFjdHMpIHtcbiAgICAgICAgICAgIGNvbnN0IGZpbGVOYW1lID0gcGF0aC5iYXNlbmFtZShhcnRpZmFjdFBhdGgpO1xuXG4gICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke2FwaVVybH0vJHtmaWxlTmFtZX1gLCB7XG4gICAgICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICAgICBBdXRob3JpemF0aW9uOiBgQmFzaWMgJHtlbmNvZGVkVXNlckFuZFBhc3N9YCxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgbWV0aG9kOiAnSEVBRCcsXG4gICAgICAgICAgICAgIC8vIFdlIHNldCByZWRpcmVjdCB0byAnbWFudWFsJyBzbyB0aGF0IHdlIGdldCB0aGUgMzAyIHJlZGlyZWN0cyBpZiB0aGUgZmlsZVxuICAgICAgICAgICAgICAvLyBhbHJlYWR5IGV4aXN0c1xuICAgICAgICAgICAgICByZWRpcmVjdDogJ21hbnVhbCcsXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gMzAyKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICBgVW5hYmxlIHRvIHB1Ymxpc2ggXCIke2ZpbGVOYW1lfVwiIGFzIGl0IGhhcyBiZWVuIHB1Ymxpc2hlZCBwcmV2aW91c2x5LiBVc2UgdGhlIFwicmVwbGFjZUV4aXN0aW5nRmlsZXNcIiBwcm9wZXJ0eSBpbiB5b3VyIEZvcmdlIGNvbmZpZyB0byBvdmVycmlkZSB0aGlzLmBcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICBhd2FpdCBhc3luY09yYShgVXBsb2FkaW5nIHJlc3VsdCAoJHtpbmRleCArIDF9LyR7bWFrZVJlc3VsdHMubGVuZ3RofSlgLCBhc3luYyAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYXBpVXJsLCB7XG4gICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJhc2ljICR7ZW5jb2RlZFVzZXJBbmRQYXNzfWAsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgICBib2R5OiBkYXRhLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBXZSB3aWxsIGdldCBhIDIwMCBvbiB0aGUgaW5pdGFsIHVwbG9hZCBhbmQgYSAyMDEgaWYgcHVibGlzaGluZyBvdmVyIHRoZSBzYW1lIHZlcnNpb25cbiAgICAgICAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAwICYmIHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAxKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmV4cGVjdGVkIHJlc3BvbnNlIGNvZGUgZnJvbSBCaXRidWNrZXQ6ICR7cmVzcG9uc2Uuc3RhdHVzfSAke3Jlc3BvbnNlLnN0YXR1c1RleHR9XFxuXFxuQm9keTpcXG4ke2F3YWl0IHJlc3BvbnNlLnRleHQoKX1gKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCB7IFB1Ymxpc2hlckJpdGJ1Y2tldCwgUHVibGlzaGVyQml0YnVja2V0Q29uZmlnIH07XG4iXSwibmFtZXMiOlsiUHVibGlzaGVyQml0YnVja2V0Q29uZmlnIiwiUHVibGlzaGVyQml0YnVja2V0IiwiUHVibGlzaGVyQmFzZSIsInB1Ymxpc2giLCJtYWtlUmVzdWx0cyIsImNvbmZpZyIsImhhc1JlcG9zaXRvcnlDb25maWciLCJyZXBvc2l0b3J5IiwicmVwbGFjZUV4aXN0aW5nRmlsZXMiLCJCb29sZWFuIiwiYXBwUGFzc3dvcmQiLCJwcm9jZXNzIiwiZW52IiwiQklUQlVDS0VUX0FQUF9QQVNTV09SRCIsInVzZXJuYW1lIiwiQklUQlVDS0VUX1VTRVJOQU1FIiwiYXV0aCIsImFwaVVybCIsIm93bmVyIiwibmFtZSIsImVuY29kZWRVc2VyQW5kUGFzcyIsIkJ1ZmZlciIsImZyb20iLCJ0b1N0cmluZyIsIkVycm9yIiwiaW5kZXgiLCJtYWtlUmVzdWx0IiwiZW50cmllcyIsImRhdGEiLCJGb3JtRGF0YSIsImFydGlmYWN0UGF0aCIsImFydGlmYWN0cyIsImFwcGVuZCIsImZzIiwiY3JlYXRlUmVhZFN0cmVhbSIsImFzeW5jT3JhIiwiZmlsZU5hbWUiLCJwYXRoIiwiYmFzZW5hbWUiLCJyZXNwb25zZSIsImZldGNoIiwiaGVhZGVycyIsIkF1dGhvcml6YXRpb24iLCJtZXRob2QiLCJyZWRpcmVjdCIsInN0YXR1cyIsImxlbmd0aCIsImJvZHkiLCJzdGF0dXNUZXh0IiwidGV4dCJdLCJtYXBwaW5ncyI6Ijs7OzsrQkFzRjZCQSxDQUF3Qjs7O2VBQXhCQSxPQUF3Qjs7OztBQXRGcEMs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