@psync/patch-package 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ - Add support for [bun](https://bun.sh) as a package manager. `patch-package`
6
+ now detects `bun.lockb` lockfiles (and bun workspaces), and accepts a
7
+ `--use-bun` flag analogous to `--use-yarn` for forcing bun.
8
+ - Package renamed to `@psync/patch-package`. The CLI command remains
9
+ `patch-package`.
package/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2017-Present David Sheldrick
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,422 @@
1
+ <p align="center">
2
+ <img src="https://ds300.github.io/patch-package/patch-package.svg" width="80%" alt="patch-package" />
3
+ </p>
4
+
5
+ `patch-package` lets app authors instantly make and keep fixes to npm
6
+ dependencies. It's a vital band-aid for those of us living on the bleeding edge.
7
+
8
+ ```sh
9
+ # fix a bug in one of your dependencies
10
+ vim node_modules/some-package/brokenFile.js
11
+
12
+ # run patch-package to create a .patch file
13
+ npx patch-package some-package
14
+
15
+ # commit the patch file to share the fix with your team
16
+ git add patches/some-package+3.14.15.patch
17
+ git commit -m "fix brokenFile.js in some-package"
18
+ ```
19
+
20
+ Patches created by `patch-package` are automatically and gracefully applied when
21
+ you use `npm`(>=5) or `yarn`.
22
+
23
+ No more waiting around for pull requests to be merged and published. No more
24
+ forking repos just to fix that one tiny thing preventing your app from working.
25
+
26
+ ## Set-up
27
+
28
+ In package.json
29
+
30
+ ```diff
31
+ "scripts": {
32
+ + "postinstall": "patch-package"
33
+ }
34
+ ```
35
+
36
+ Then
37
+
38
+ ### npm
39
+
40
+ npm i patch-package
41
+
42
+ You can use `--save-dev` if you don't need to run npm in production, e.g. if
43
+ you're making a web frontend.
44
+
45
+ ### yarn v1
46
+
47
+ yarn add patch-package postinstall-postinstall
48
+
49
+ You can use `--dev` if you don't need to run yarn in production, e.g. if you're
50
+ making a web frontend.
51
+
52
+ To understand why yarn needs the `postinstall-postinstall` package see:
53
+ [Why use postinstall-postinstall](#why-use-postinstall-postinstall-with-yarn)
54
+
55
+ ### yarn workspaces
56
+
57
+ Same as for yarn ☝️ Note that if you want to patch un-hoisted packages you'll
58
+ need to repeat the setup process for the child package. Also make sure you're in
59
+ the child package directory when you run `patch-package` to generate the patch
60
+ files.
61
+
62
+ ### yarn v2+
63
+
64
+ yarn 2+ have native support for patching dependencies via
65
+ [`yarn patch`](https://yarnpkg.com/cli/patch). You do not need to use
66
+ patch-package on these projects.
67
+
68
+ ### bun
69
+
70
+ bun add patch-package
71
+
72
+ You can use `--dev` if you don't need to run bun in production, e.g. if you're
73
+ making a web frontend.
74
+
75
+ ### pnpm
76
+
77
+ pnpm has native support for patching dependencies via
78
+ [`pnpm patch`](https://pnpm.io/cli/patch). You do not need to use patch-package
79
+ on these projects.
80
+
81
+ ### Heroku
82
+
83
+ For `patch-package` to work on Heroku applications, you must specify
84
+ [`NPM_CONFIG_PRODUCTION=false` or `YARN_PRODUCTION=false`](https://devcenter.heroku.com/articles/nodejs-support#package-installation).
85
+ See [this issue](https://github.com/ds300/patch-package/issues/130) for more
86
+ details.
87
+
88
+ ### Docker and CI
89
+
90
+ - If having errors about working directory ("cannot run in wd [...]") when
91
+ building in Docker, you might need to adjust configuration in `.npmrc`. See
92
+ [#185](https://github.com/ds300/patch-package/issues/185).
93
+ - In your `Dockerfile`, remember to copy over the patch files _before_ running
94
+ `[npm|yarn] install`
95
+ - If you cache `node_modules` rather than running `yarn install` every time,
96
+ make sure that the `patches` dir is included in your cache key somehow.
97
+ Otherwise if you update a patch then the change may not be reflected on
98
+ subsequent CI runs.
99
+
100
+ ### CircleCI
101
+
102
+ Create a hash of your patches before loading/saving your cache. If using a Linux
103
+ machine, run `md5sum patches/* > patches.hash`. If running on a macOS machine,
104
+ use `md5 patches/* > patches.hash`
105
+
106
+ ```yaml
107
+ - run:
108
+ name: patch-package hash
109
+ command: md5sum patches/* > patches.hash
110
+ ```
111
+
112
+ Then, update your hash key to include a checksum of that file:
113
+
114
+ ```yaml
115
+ - restore_cache:
116
+ key:
117
+ app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash"
118
+ }}
119
+ ```
120
+
121
+ As well as the save_cache
122
+
123
+ ```yaml
124
+ - save_cache:
125
+ key:
126
+ app-node_modules-v1-{{ checksum "yarn.lock" }}-{{ checksum "patches.hash"
127
+ }}
128
+ paths:
129
+ - ./node_modules
130
+ ```
131
+
132
+ ## Usage
133
+
134
+ ### Making patches
135
+
136
+ First make changes to the files of a particular package in your node_modules
137
+ folder, then run
138
+
139
+ yarn patch-package package-name
140
+
141
+ or use npx (included with `npm > 5.2`)
142
+
143
+ npx patch-package package-name
144
+
145
+ where `package-name` matches the name of the package you made changes to.
146
+
147
+ If this is the first time you've used `patch-package`, it will create a folder
148
+ called `patches` in the root dir of your app. Inside will be a file called
149
+ `package-name+0.44.0.patch` or something, which is a diff between normal old
150
+ `package-name` and your fixed version. Commit this to share the fix with your
151
+ team.
152
+
153
+ #### Options
154
+
155
+ - `--create-issue`
156
+
157
+ For packages whose source is hosted on GitHub this option opens a web browser
158
+ with a draft issue based on your diff.
159
+
160
+ - `--use-yarn`
161
+
162
+ By default, patch-package checks whether you use npm, yarn or bun based on
163
+ which lockfile you have. If you have multiple lockfiles, it uses npm by
164
+ default (in cases where npm is not available, it will resort to yarn). Set
165
+ this option to override that default and always use yarn.
166
+
167
+ - `--use-bun`
168
+
169
+ Similar to --use-yarn, but for bun. If both --use-yarn and --use-bun are
170
+ specified, --use-yarn takes precedence.
171
+
172
+ - `--exclude <regexp>`
173
+
174
+ Ignore paths matching the regexp when creating patch files. Paths are relative
175
+ to the root dir of the package to be patched.
176
+
177
+ Default value: `package\\.json$`
178
+
179
+ - `--include <regexp>`
180
+
181
+ Only consider paths matching the regexp when creating patch files. Paths are
182
+ relative to the root dir of the package to be patched.
183
+
184
+ Default value: `.*`
185
+
186
+ - `--case-sensitive-path-filtering`
187
+
188
+ Make regexps used in --include or --exclude filters case-sensitive.
189
+
190
+ - `--patch-dir`
191
+
192
+ Specify the name for the directory in which to put the patch files.
193
+
194
+ #### Nested packages
195
+
196
+ If you are trying to patch a package at, e.g.
197
+ `node_modules/package/node_modules/another-package` you can just put a `/`
198
+ between the package names:
199
+
200
+ npx patch-package package/another-package
201
+
202
+ It works with scoped packages too
203
+
204
+ npx patch-package @my/package/@my/other-package
205
+
206
+ ### Updating patches
207
+
208
+ Use exactly the same process as for making patches in the first place, i.e. make
209
+ more changes, run patch-package, commit the changes to the patch file.
210
+
211
+ ### Applying patches
212
+
213
+ Run `patch-package` without arguments to apply all patches in your project.
214
+
215
+ #### Options
216
+
217
+ - `--error-on-fail`
218
+
219
+ Forces patch-package to exit with code 1 after failing.
220
+
221
+ When running locally patch-package always exits with 0 by default. This
222
+ happens even after failing to apply patches because otherwise yarn.lock and
223
+ package.json might get out of sync with node_modules, which can be very
224
+ confusing.
225
+
226
+ `--error-on-fail` is **switched on** by default on CI.
227
+
228
+ See https://github.com/ds300/patch-package/issues/86 for background.
229
+
230
+ - `--reverse`
231
+
232
+ Un-applies all patches.
233
+
234
+ Note that this will fail if the patched files have changed since being
235
+ patched. In that case, you'll probably need to re-install `node_modules`.
236
+
237
+ This option was added to help people using CircleCI avoid
238
+ [an issue around caching and patch file updates](https://github.com/ds300/patch-package/issues/37)
239
+ but might be useful in other contexts too.
240
+
241
+ - `--patch-dir`
242
+
243
+ Specify the name for the directory in which the patch files are located
244
+
245
+ #### Notes
246
+
247
+ To apply patches individually, you may use `git`:
248
+
249
+ git apply --ignore-whitespace patches/package-name+0.44.2.patch
250
+
251
+ or `patch` in unixy environments:
252
+
253
+ patch -p1 -i patches/package-name+0.44.2.patch
254
+
255
+ ### Dev-only patches
256
+
257
+ If you deploy your package to production (e.g. your package is a server) then
258
+ any patched `devDependencies` will not be present when patch-package runs in
259
+ production. It will happily ignore those patch files if the package to be
260
+ patched is listed directly in the `devDependencies` of your package.json. If
261
+ it's a transitive dependency patch-package can't detect that it is safe to
262
+ ignore and will throw an error. To fix this, mark patches for transitive dev
263
+ dependencies as dev-only by renaming from, e.g.
264
+
265
+ package-name+0.44.0.patch
266
+
267
+ to
268
+
269
+ package-name+0.44.0.dev.patch
270
+
271
+ This will allow those patch files to be safely ignored when
272
+ `NODE_ENV=production`.
273
+
274
+ ### Creating multiple patches for the same package
275
+
276
+ _💡 This is an advanced feature and is not recommended unless you really, really
277
+ need it._
278
+
279
+ Let's say you have a patch for react-native called
280
+
281
+ - `patches/react-native+0.72.0.patch`
282
+
283
+ If you want to add another patch file to `react-native`, you can use the
284
+ `--append` flag while supplying a name for the patch.
285
+
286
+ Just make you changes inside `node_modules/react-native` then run e.g.
287
+
288
+ npx patch-package react-native --append 'fix-touchable-opacity'
289
+
290
+ This will create a new patch file while renaming the old patch file so that you
291
+ now have:
292
+
293
+ - `patches/react-native+0.72.0+001+initial.patch`
294
+ - `patches/react-native+0.72.0+002+fix-touchable-opacity.patch`
295
+
296
+ The patches are ordered in a sequence, so that they can build on each other if
297
+ necessary. **Think of these as commits in a git history**.
298
+
299
+ #### Updating a sequenced patch file
300
+
301
+ If the patch file is the last one in the sequence, you can just make your
302
+ changes inside e.g. `node_modules/react-native` and then run
303
+
304
+ npx patch-package react-native
305
+
306
+ This will update the last patch file in the sequence.
307
+
308
+ If the patch file is not the last one in the sequence **you need to use the
309
+ `--rebase` feature** to un-apply the succeeding patch files first.
310
+
311
+ Using the example above, let's say you want to update the `001+initial` patch
312
+ but leave the other patch alone. You can run
313
+
314
+ npx patch-package react-native --rebase patches/react-native+0.72.0+001+initial.patch
315
+
316
+ This will undo the `002-fix-touchable-opacity` patch file. You can then make
317
+ your changes and run
318
+
319
+ npx patch-package react-native
320
+
321
+ to finish the rebase by updating the `001+initial` patch file and re-apply the
322
+ `002-fix-touchable-opacity` patch file, leaving you with all patches applied and
323
+ up-to-date.
324
+
325
+ #### Inserting a new patch file in the middle of an existing sequence
326
+
327
+ Using the above example, let's say you want to insert a new patch file between
328
+ the `001+initial` and `002+fix-touchable-opacity` patch files. You can run
329
+
330
+ npx patch-package react-native --rebase patches/react-native+0.72.0+001+initial.patch
331
+
332
+ This will undo the `002-fix-touchable-opacity` patch file. You can then make any
333
+ changes you want to insert in a new patch file and run
334
+
335
+ npx patch-package react-native --append 'fix-console-warnings'
336
+
337
+ This will create a new patch file while renaming any successive patches to
338
+ maintain the sequence order, leaving you with
339
+
340
+ - `patches/react-native+0.72.0+001+initial.patch`
341
+ - `patches/react-native+0.72.0+002+fix-console-warnings.patch`
342
+ - `patches/react-native+0.72.0+003+fix-touchable-opacity.patch`
343
+
344
+ To insert a new patch file at the start of the sequence, you can run
345
+
346
+ npx patch-package react-native --rebase 0
347
+
348
+ Which will un-apply all patch files in the sequence. Then follow the process
349
+ above to create a new patch file numbered `001`.
350
+
351
+ #### Deleting a sequenced patch file
352
+
353
+ To delete a sequenced patch file, just delete it, then remove and reinstall your
354
+ `node_modules` folder.
355
+
356
+ If you deleted one of the patch files other than the last one, you don't need to
357
+ update the sequence numbers in the successive patch file names, but you might
358
+ want to do so to keep things tidy.
359
+
360
+ #### Partially applying a broken patch file
361
+
362
+ Normally patch application is atomic per patch file. i.e. if a patch file
363
+ contains an error anywhere then none of the changes in the patch file will be
364
+ applied and saved to disk.
365
+
366
+ This can be problematic if you have a patch with many changes and you want to
367
+ keep some of them and update others.
368
+
369
+ In this case you can use the `--partial` option. Patch-package will apply as
370
+ many of the changes as it can and then leave it to you to fix the rest.
371
+
372
+ Any errors encountered will be written to a file `./patch-package-errors.log` to
373
+ help you keep track of what needs fixing.
374
+
375
+ ## Benefits of patching over forking
376
+
377
+ - Sometimes forks need extra build steps, e.g. with react-native for Android.
378
+ Forget that noise.
379
+ - Get told in big red letters when the dependency changed and you need to check
380
+ that your fix is still valid.
381
+ - Keep your patches colocated with the code that depends on them.
382
+ - Patches can be reviewed as part of your normal review process, forks probably
383
+ can't
384
+
385
+ ## When to fork instead
386
+
387
+ - The change is too consequential to be developed in situ.
388
+ - The change would be useful to other people as-is.
389
+ - You can afford to make a proper PR to upstream.
390
+
391
+ ## Isn't this dangerous?
392
+
393
+ Nope. The technique is quite robust. Here are some things to keep in mind
394
+ though:
395
+
396
+ - It's easy to forget to run `yarn` or `npm` when switching between branches
397
+ that do and don't have patch files.
398
+ - Long lived patches can be costly to maintain if they affect an area of code
399
+ that is updated regularly and you want to update the package regularly too.
400
+ - Big semantic changes can be hard to review. Keep them small and obvious or add
401
+ plenty of comments.
402
+ - Changes can also impact the behaviour of other untouched packages. It's
403
+ normally obvious when this will happen, and often desired, but be careful
404
+ nonetheless.
405
+
406
+ ## Why use postinstall-postinstall with Yarn?
407
+
408
+ Most times when you do a `yarn`, `yarn add`, `yarn remove`, or `yarn install`
409
+ (which is the same as just `yarn`) Yarn will completely replace the contents of
410
+ your node_modules with freshly unpackaged modules. patch-package uses the
411
+ `postinstall` hook to modify these fresh modules, so that they behave well
412
+ according to your will.
413
+
414
+ Yarn only runs the `postinstall` hook after `yarn` and `yarn add`, but not after
415
+ `yarn remove`. The `postinstall-postinstall` package is used to make sure your
416
+ `postinstall` hook gets executed even after a `yarn remove`.
417
+
418
+ ## License
419
+
420
+ MIT
421
+
422
+ [![Empowered by Futurice's open source sponsorship program](https://img.shields.io/badge/sponsor-chilicorn-ff69b4.svg)](http://futurice.com/blog/sponsoring-free-time-open-source-activities?utm_source=github&utm_medium=spice&utm_campaign=patch-package)
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseNameAndVersion = parseNameAndVersion;
4
+ exports.getPackageDetailsFromPatchFilename = getPackageDetailsFromPatchFilename;
5
+ exports.getPatchDetailsFromCliString = getPatchDetailsFromCliString;
6
+ const path_1 = require("./path");
7
+ function parseNameAndVersion(str) {
8
+ const parts = str
9
+ .split("+")
10
+ .map((s) => s.trim())
11
+ .filter(Boolean);
12
+ if (parts.length === 0) {
13
+ return null;
14
+ }
15
+ if (parts.length === 1) {
16
+ return { packageName: str };
17
+ }
18
+ const versionIndex = parts.findIndex((part) => part.match(/^\d+\.\d+\.\d+.*$/));
19
+ if (versionIndex === -1) {
20
+ const [scope, name] = parts;
21
+ return { packageName: `${scope}/${name}` };
22
+ }
23
+ const nameParts = parts.slice(0, versionIndex);
24
+ let packageName;
25
+ switch (nameParts.length) {
26
+ case 0:
27
+ return null;
28
+ case 1:
29
+ packageName = nameParts[0];
30
+ break;
31
+ case 2:
32
+ const [scope, name] = nameParts;
33
+ packageName = `${scope}/${name}`;
34
+ break;
35
+ default:
36
+ return null;
37
+ }
38
+ const version = parts[versionIndex];
39
+ const sequenceParts = parts.slice(versionIndex + 1);
40
+ if (sequenceParts.length === 0) {
41
+ return { packageName, version };
42
+ }
43
+ // expect sequenceParts[0] to be a number, strip leading 0s
44
+ const sequenceNumber = parseInt(sequenceParts[0].replace(/^0+/, ""), 10);
45
+ if (isNaN(sequenceNumber)) {
46
+ return null;
47
+ }
48
+ switch (sequenceParts.length) {
49
+ case 1: {
50
+ return { packageName, version, sequenceNumber };
51
+ }
52
+ case 2: {
53
+ return {
54
+ packageName,
55
+ version,
56
+ sequenceName: sequenceParts[1],
57
+ sequenceNumber,
58
+ };
59
+ }
60
+ default: {
61
+ return null;
62
+ }
63
+ }
64
+ return null;
65
+ }
66
+ function getPackageDetailsFromPatchFilename(patchFilename) {
67
+ const parts = patchFilename
68
+ .replace(/(\.dev)?\.patch$/, "")
69
+ .split("++")
70
+ .map(parseNameAndVersion)
71
+ .filter((x) => x !== null);
72
+ if (parts.length === 0) {
73
+ return null;
74
+ }
75
+ const lastPart = parts[parts.length - 1];
76
+ if (!lastPart.version) {
77
+ return null;
78
+ }
79
+ return {
80
+ name: lastPart.packageName,
81
+ version: lastPart.version,
82
+ path: (0, path_1.join)("node_modules", parts.map(({ packageName: name }) => name).join("/node_modules/")),
83
+ patchFilename,
84
+ pathSpecifier: parts.map(({ packageName: name }) => name).join("/"),
85
+ humanReadablePathSpecifier: parts
86
+ .map(({ packageName: name }) => name)
87
+ .join(" => "),
88
+ isNested: parts.length > 1,
89
+ packageNames: parts.map(({ packageName: name }) => name),
90
+ isDevOnly: patchFilename.endsWith(".dev.patch"),
91
+ sequenceName: lastPart.sequenceName,
92
+ sequenceNumber: lastPart.sequenceNumber,
93
+ };
94
+ }
95
+ function getPatchDetailsFromCliString(specifier) {
96
+ const parts = specifier.split("/");
97
+ const packageNames = [];
98
+ let scope = null;
99
+ for (let i = 0; i < parts.length; i++) {
100
+ if (parts[i].startsWith("@")) {
101
+ if (scope) {
102
+ return null;
103
+ }
104
+ scope = parts[i];
105
+ }
106
+ else {
107
+ if (scope) {
108
+ packageNames.push(`${scope}/${parts[i]}`);
109
+ scope = null;
110
+ }
111
+ else {
112
+ packageNames.push(parts[i]);
113
+ }
114
+ }
115
+ }
116
+ const path = (0, path_1.join)("node_modules", packageNames.join("/node_modules/"));
117
+ return {
118
+ packageNames,
119
+ path,
120
+ name: packageNames[packageNames.length - 1],
121
+ humanReadablePathSpecifier: packageNames.join(" => "),
122
+ isNested: packageNames.length > 1,
123
+ pathSpecifier: specifier,
124
+ };
125
+ }
126
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGFja2FnZURldGFpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvUGFja2FnZURldGFpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFtQkEsa0RBcUVDO0FBRUQsZ0ZBcUNDO0FBRUQsb0VBbUNDO0FBcEtELGlDQUE2QjtBQW1CN0IsU0FBZ0IsbUJBQW1CLENBQ2pDLEdBQVc7SUFPWCxNQUFNLEtBQUssR0FBRyxHQUFHO1NBQ2QsS0FBSyxDQUFDLEdBQUcsQ0FBQztTQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1NBQ3BCLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUNsQixJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDdkIsT0FBTyxJQUFJLENBQUE7SUFDYixDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3ZCLE9BQU8sRUFBRSxXQUFXLEVBQUUsR0FBRyxFQUFFLENBQUE7SUFDN0IsQ0FBQztJQUNELE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUM1QyxJQUFJLENBQUMsS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQ2hDLENBQUE7SUFDRCxJQUFJLFlBQVksS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFBO1FBQzNCLE9BQU8sRUFBRSxXQUFXLEVBQUUsR0FBRyxLQUFLLElBQUksSUFBSSxFQUFFLEVBQUUsQ0FBQTtJQUM1QyxDQUFDO0lBQ0QsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUE7SUFDOUMsSUFBSSxXQUFXLENBQUE7SUFDZixRQUFRLFNBQVMsQ0FBQyxN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Q3pDLEtBQUssR0FBRyxJQUFJLENBQUE7WUFDZCxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtZQUM3QixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxNQUFNLElBQUksR0FBRyxJQUFBLFdBQUksRUFBQyxjQUFjLEVBQUUsWUFBWSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUE7SUFFdEUsT0FBTztRQUNMLFlBQVk7UUFDWixJQUFJO1FBQ0osSUFBSSxFQUFFLFlBQVksQ0FBQyxZQUFZLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUMzQywwQkFBMEIsRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUNyRCxRQUFRLEVBQUUsWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDO1FBQ2pDLGFBQWEsRUFBRSxTQUFTO0tBQ3pCLENBQUE7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgam9pbiB9IGZyb20gXCIuL3BhdGhcIlxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBQYWNrYWdlRGV0YWlscyB7XHJcbiAgaHVtYW5SZWFkYWJsZVBhdGhTcGVjaWZpZXI6IHN0cmluZ1xyXG4gIHBhdGhTcGVjaWZpZXI6IHN0cmluZ1xyXG4gIHBhdGg6IHN0cmluZ1xyXG4gIG5hbWU6IHN0cmluZ1xyXG4gIGlzTmVzdGVkOiBib29sZWFuXHJcbiAgcGFja2FnZU5hbWVzOiBzdHJpbmdbXVxyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFBhdGNoZWRQYWNrYWdlRGV0YWlscyBleHRlbmRzIFBhY2thZ2VEZXRhaWxzIHtcclxuICB2ZXJzaW9uOiBzdHJpbmdcclxuICBwYXRjaEZpbGVuYW1lOiBzdHJpbmdcclxuICBpc0Rldk9ubHk6IGJvb2xlYW5cclxuICBzZXF1ZW5jZU5hbWU/OiBzdHJpbmdcclxuICBzZXF1ZW5jZU51bWJlcj86IG51bWJlclxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VOYW1lQW5kVmVyc2lvbihcclxuICBzdHI6IHN0cmluZyxcclxuKToge1xyXG4gIHBhY2thZ2VOYW1lOiBzdHJpbmdcclxuICB2ZXJzaW9uPzogc3RyaW5nXHJcbiAgc2VxdWVuY2VOYW1lPzogc3RyaW5nXHJcbiAgc2VxdWVuY2VOdW1iZXI/OiBudW1iZXJcclxufSB8IG51bGwge1xyXG4gIGNvbnN0IHBhcnRzID0gc3RyXHJcbiAgICAuc3BsaXQoXCIrXCIpXHJcbiAgICAubWFwKChzKSA9PiBzLnRyaW0oKSlcclxuICAgIC5maWx0ZXIoQm9vbGVhbilcclxuICBpZiAocGFydHMubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbnVsbFxyXG4gIH1cclxuICBpZiAocGFydHMubGVuZ3RoID09PSAxKSB7XHJcbiAgICByZXR1cm4geyBwYWNrYWdlTmFtZTogc3RyIH1cclxuICB9XHJcbiAgY29uc3QgdmVyc2lvbkluZGV4ID0gcGFydHMuZmluZEluZGV4KChwYXJ0KSA9PlxyXG4gICAgcGFydC5tYXRjaCgvXlxcZCtcXC5cXGQrXFwuXFxkKy4qJC8pLFxyXG4gIClcclxuICBpZiAodmVyc2lvbkluZGV4ID09PSAtMSkge1xyXG4gICAgY29uc3QgW3Njb3BlLCBuYW1lXSA9IHBhcnRzXHJcbiAgICByZXR1cm4geyBwYWNrYWdlTmFtZTogYCR7c2NvcGV9LyR7bmFtZX1gIH1cclxuICB9XHJcbiAgY29uc3QgbmFtZVBhcnRzID0gcGFydHMuc2xpY2UoMCwgdmVyc2lvbkluZGV4KVxyXG4gIGxldCBwYWNrYWdlTmFtZVxyXG4gIHN3aXRjaCAobmFtZVBhcnRzLmxlbmd0aCkge1xyXG4gICAgY2FzZSAwOlxyXG4gICAgICByZXR1cm4gbnVsbFxyXG4gICAgY2FzZSAxOlxyXG4gICAgICBwYWNrYWdlTmFtZSA9IG5hbWVQYXJ0c1swXVxyXG4gICAgICBicmVha1xyXG4gICAgY2FzZSAyOlxyXG4gICAgICBjb25zdCBbc2NvcGUsIG5hbWVdID0gbmFtZVBhcnRzXHJcbiAgICAgIHBhY2thZ2VOYW1lID0gYCR7c2NvcGV9LyR7bmFtZX1gXHJcbiAgICAgIGJyZWFrXHJcbiAgICBkZWZhdWx0OlxyXG4gICAgICByZXR1cm4gbnVsbFxyXG4gIH1cclxuXHJcbiAgY29uc3QgdmVyc2lvbiA9IHBhcnRzW3ZlcnNpb25JbmRleF1cclxuICBjb25zdCBzZXF1ZW5jZVBhcnRzID0gcGFydHMuc2xpY2UodmVyc2lvbkluZGV4ICsgMSlcclxuICBpZiAoc2VxdWVuY2VQYXJ0cy5sZW5ndGggPT09IDApIHtcclxuICAgIHJldHVybiB7IHBhY2thZ2VOYW1lLCB2ZXJzaW9uIH1cclxuICB9XHJcblxyXG4gIC8vIGV4cGVjdCBzZXF1ZW5jZVBhcnRzWzBdIHRvIGJlIGEgbnVtYmVyLCBzdHJpcCBsZWFkaW5nIDBzXHJcbiAgY29uc3Qgc2VxdWVuY2VOdW1iZXIgPSBwYXJzZUludChzZXF1ZW5jZVBhcnRzWzBdLnJlcGxhY2UoL14wKy8sIFwiXCIpLCAxMClcclxuICBpZiAoaXNOYU4oc2VxdWVuY2VOdW1iZXIpKSB7XHJcbiAgICByZXR1cm4gbnVsbFxyXG4gIH1cclxuICBzd2l0Y2ggKHNlcXVlbmNlUGFydHMubGVuZ3RoKSB7XHJcbiAgICBjYXNlIDE6IHtcclxuICAgICAgcmV0dXJuIHsgcGFja2FnZU5hbWUsIHZlcnNpb24sIHNlcXVlbmNlTnVtYmVyIH1cclxuICAgIH1cclxuICAgIGNhc2UgMjoge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIHBhY2thZ2VOYW1lLFxyXG4gICAgICAgIHZlcnNpb24sXHJcbiAgICAgICAgc2VxdWVuY2VOYW1lOiBzZXF1ZW5jZVBhcnRzWzFdLFxyXG4gICAgICAgIHNlcXVlbmNlTnVtYmVyLFxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBkZWZhdWx0OiB7XHJcbiAgICAgIHJldHVybiBudWxsXHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBudWxsXHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQYWNrYWdlRGV0YWlsc0Zyb21QYXRjaEZpbGVuYW1lKFxyXG4gIHBhdGNoRmlsZW5hbWU6IHN0cmluZyxcclxuKTogUGF0Y2hlZFBhY2thZ2VEZXRhaWxzIHwgbnVsbCB7XHJcbiAgY29uc3QgcGFydHMgPSBwYXRjaEZpbGVuYW1lXHJcbiAgICAucmVwbGFjZSgvKFxcLmRldik/XFwucGF0Y2gkLywgXCJcIilcclxuICAgIC5zcGxpdChcIisrXCIpXHJcbiAgICAubWFwKHBhcnNlTmFtZUFuZFZlcnNpb24pXHJcbiAgICAuZmlsdGVyKCh4KTogeCBpcyBOb25OdWxsYWJsZTx0eXBlb2YgeD4gPT4geCAhPT0gbnVsbClcclxuXHJcbiAgaWYgKHBhcnRzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgcmV0dXJuIG51bGxcclxuICB9XHJcblxyXG4gIGNvbnN0IGxhc3RQYXJ0ID0gcGFydHNbcGFydHMubGVuZ3RoIC0gMV1cclxuXHJcbiAgaWYgKCFsYXN0UGFydC52ZXJzaW9uKSB7XHJcbiAgICByZXR1cm4gbnVsbFxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIHtcclxuICAgIG5hbWU6IGxhc3RQYXJ0LnBhY2thZ2VOYW1lLFxyXG4gICAgdmVyc2lvbjogbGFzdFBhcnQudmVyc2lvbixcclxuICAgIHBhdGg6IGpvaW4oXHJcbiAgICAgIFwibm9kZV9tb2R1bGVzXCIsXHJcbiAgICAgIHBhcnRzLm1hcCgoeyBwYWNrYWdlTmFtZTogbmFtZSB9KSA9PiBuYW1lKS5qb2luKFwiL25vZGVfbW9kdWxlcy9cIiksXHJcbiAgICApLFxyXG4gICAgcGF0Y2hGaWxlbmFtZSxcclxuICAgIHBhdGhTcGVjaWZpZXI6IHBhcnRzLm1hcCgoeyBwYWNrYWdlTmFtZTogbmFtZSB9KSA9PiBuYW1lKS5qb2luKFwiL1wiKSxcclxuICAgIGh1bWFuUmVhZGFibGVQYXRoU3BlY2lmaWVyOiBwYXJ0c1xyXG4gICAgICAubWFwKCh7IHBhY2thZ2VOYW1lOiBuYW1lIH0pID0+IG5hbWUpXHJcbiAgICAgIC5qb2luKFwiID0+IFwiKSxcclxuICAgIGlzTmVzdGVkOiBwYXJ0cy5sZW5ndGggPiAxLFxyXG4gICAgcGFja2FnZU5hbWVzOiBwYXJ0cy5tYXAoKHsgcGFja2FnZU5hbWU6IG5hbWUgfSkgPT4gbmFtZSksXHJcbiAgICBpc0Rldk9ubHk6IHBhdGNoRmlsZW5hbWUuZW5kc1dpdGgoXCIuZGV2LnBhdGNoXCIpLFxyXG4gICAgc2VxdWVuY2VOYW1lOiBsYXN0UGFydC5zZXF1ZW5jZU5hbWUsXHJcbiAgICBzZXF1ZW5jZU51bWJlcjogbGFzdFBhcnQuc2VxdWVuY2VOdW1iZXIsXHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UGF0Y2hEZXRhaWxzRnJvbUNsaVN0cmluZyhcclxuICBzcGVjaWZpZXI6IHN0cmluZyxcclxuKTogUGFja2FnZURldGFpbHMgfCBudWxsIHtcclxuICBjb25zdCBwYXJ0cyA9IHNwZWNpZmllci5zcGxpdChcIi9cIilcclxuXHJcbiAgY29uc3QgcGFja2FnZU5hbWVzID0gW11cclxuXHJcbiAgbGV0IHNjb3BlOiBzdHJpbmcgfCBudWxsID0gbnVsbFxyXG5cclxuICBmb3IgKGxldCBpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBpZiAocGFydHNbaV0uc3RhcnRzV2l0aChcIkBcIikpIHtcclxuICAgICAgaWYgKHNjb3BlKSB7XHJcbiAgICAgICAgcmV0dXJuIG51bGxcclxuICAgICAgfVxyXG4gICAgICBzY29wZSA9IHBhcnRzW2ldXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBpZiAoc2NvcGUpIHtcclxuICAgICAgICBwYWNrYWdlTmFtZXMucHVzaChgJHtzY29wZX0vJHtwYXJ0c1tpXX1gKVxyXG4gICAgICAgIHNjb3BlID0gbnVsbFxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHBhY2thZ2VOYW1lcy5wdXNoKHBhcnRzW2ldKVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBjb25zdCBwYXRoID0gam9pbihcIm5vZGVfbW9kdWxlc1wiLCBwYWNrYWdlTmFtZXMuam9pbihcIi9ub2RlX21vZHVsZXMvXCIpKVxyXG5cclxuICByZXR1cm4ge1xyXG4gICAgcGFja2FnZU5hbWVzLFxyXG4gICAgcGF0aCxcclxuICAgIG5hbWU6IHBhY2thZ2VOYW1lc1twYWNrYWdlTmFtZXMubGVuZ3RoIC0gMV0sXHJcbiAgICBodW1hblJlYWRhYmxlUGF0aFNwZWNpZmllcjogcGFja2FnZU5hbWVzLmpvaW4oXCIgPT4gXCIpLFxyXG4gICAgaXNOZXN0ZWQ6IHBhY2thZ2VOYW1lcy5sZW5ndGggPiAxLFxyXG4gICAgcGF0aFNwZWNpZmllcjogc3BlY2lmaWVyLFxyXG4gIH1cclxufVxyXG4iXX0=