presetter 3.1.1 → 3.4.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/README.md CHANGED
@@ -4,14 +4,14 @@
4
4
 
5
5
  🏄🏻 _Setup build settings from a template, quick and right!_
6
6
 
7
- •   [Quick Start](#quick-start)   •   [Usage](#usage)   •   [Customisation](#customisation)   •
7
+ •   [Quick Start](#quick-start)   •   [Usage](#usage)   •   [Customization](#customization)   •
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/presetter?style=flat-square)](https://github.com/alvis/presetter/releases)
10
10
  [![build](https://img.shields.io/github/workflow/status/alvis/presetter/code%20test?style=flat-square)](https://github.com/alvis/presetter/actions)
11
11
  [![maintainability](https://img.shields.io/codeclimate/maintainability/alvis/presetter?style=flat-square)](https://codeclimate.com/github/alvis/presetter/maintainability)
12
12
  [![coverage](https://img.shields.io/codeclimate/coverage/alvis/presetter?style=flat-square)](https://codeclimate.com/github/alvis/presetter/test_coverage)
13
13
  [![security](https://img.shields.io/snyk/vulnerabilities/github/alvis/presetter/packages/presetter/package.json.svg?style=flat-square)](https://snyk.io/test/github/alvis/presetter?targetFile=packages/presetter/package.json&style=flat-square)
14
- [![dependencies](https://img.shields.io/david/alvis/presetter?path=packages/presetter&style=flat-square)](https://david-dm.org/alvis/presetter?path=packages/presetter)
14
+ [![dependencies](https://img.shields.io/librariesio/release/npm/presetter-presetter?style=flat-square)](https://libraries.io/npm/presetter-presetter)
15
15
  [![license](https://img.shields.io/github/license/alvis/presetter.svg?style=flat-square)](https://github.com/alvis/presetter/blob/master/LICENSE)
16
16
 
17
17
  </div>
@@ -21,7 +21,7 @@ How many dev dependencies you have to install before you can kick start a projec
21
21
 
22
22
  What's more, what if you want to update configs for all projects? :man_facepalming:
23
23
 
24
- **Presetter is a utility for setting up building tools for your project from a template.** This means with just only two dev packages, namely this package and your favourite template preset, all essential development packages, such as typescript, eslint and jest, together with their configuration files provided by the preset, are automatically setup for you upon the project's initialisation.
24
+ **Presetter is a utility for setting up building tools for your project from a template.** This means with just only two dev packages, namely this package and your favorite template preset, all essential development packages, such as typescript, eslint and jest, together with their configuration files provided by the preset, are automatically setup for you upon the project's initialization.
25
25
 
26
26
  ---
27
27
 
@@ -128,13 +128,13 @@ _PROTIPS_: Install `presetter` globally via `npm install -g presetter` and you c
128
128
 
129
129
  ---
130
130
 
131
- ## Customisation
131
+ ## Customization
132
132
 
133
- Presetter support customisation in two ways.
133
+ Presetter support customization in two ways.
134
134
 
135
- #### Preset Customisation
135
+ #### Preset Customization
136
136
 
137
- If your preset support customisation, you can supply the customisation parameter via the `config` field in `.presetterrc`.
137
+ If your preset support customization, you can supply the customization parameter via the `config` field in `.presetterrc`.
138
138
  e.g. For [presetter-preset-essentials](https://github.com/alvis/presetter/tree/master/packages/preset-essentials), you can adding an expression to `.gitignore` with the following in `.presetterrc`:
139
139
 
140
140
  ```json
package/lib/content.d.ts CHANGED
@@ -1,7 +1,49 @@
1
- import type { DynamicAsset, DynamicAssetField, PresetAsset, PresetContext, RequiredResolution, ResolvedPresetContext, Template } from './types';
2
- export declare function customise(template: Template, custom?: string[] | Record<string, unknown>): Template;
3
- export declare function generateContent(assets: PresetAsset[], context: PresetContext): Promise<Record<string, Template>>;
4
- export declare function getConfigKey(filename: string): string;
5
- export declare function getVariable(assets: PresetAsset[], context: PresetContext): Record<string, string>;
6
- export declare function resolveContext(assets: PresetAsset[], context: PresetContext): Promise<ResolvedPresetContext>;
7
- export declare function resolveDynamicMap<F extends DynamicAssetField>(assets: PresetAsset[], context: ResolvedPresetContext<RequiredResolution<F>>, field: F): Promise<Record<string, DynamicAsset<F>>>;
1
+ import type { MergeMode } from './template';
2
+ import type { Config, PresetContext, PresetGraph, PresetNode, PresetterConfig, ResolvedPresetContext, Template } from './types';
3
+ export declare function resolveContext(_: {
4
+ graph: PresetGraph;
5
+ context: PresetContext;
6
+ }): Promise<ResolvedPresetContext>;
7
+ export declare function resolveNoSymlinks(_: {
8
+ graph: PresetGraph;
9
+ context: ResolvedPresetContext<'variable'>;
10
+ }): Promise<string[]>;
11
+ export declare function resolveSupplementaryConfig(_: {
12
+ graph: PresetGraph;
13
+ context: ResolvedPresetContext<'variable'>;
14
+ }): Promise<Record<string, Config>>;
15
+ export declare function resolveSupplementaryConfigFromNode(_: {
16
+ node: PresetNode;
17
+ context: ResolvedPresetContext<'variable'>;
18
+ }): Promise<Record<string, Config>>;
19
+ export declare function resolveSupplementaryScripts(_: {
20
+ graph: PresetGraph;
21
+ context: ResolvedPresetContext<'variable'>;
22
+ }): Promise<Record<string, string>>;
23
+ export declare function resolveSupplementaryScriptsFromNode(_: {
24
+ node: PresetNode;
25
+ context: ResolvedPresetContext<'variable'>;
26
+ }): Promise<Record<string, string>>;
27
+ export declare function resolveVariable(_: {
28
+ graph: PresetGraph;
29
+ config: PresetterConfig;
30
+ }): Record<string, string>;
31
+ export declare function mergeTemplate(current: Record<string, Template>, candidate: Record<string, Template>, options: {
32
+ mode: MergeMode;
33
+ }): Record<string, Template>;
34
+ export declare function resolveTemplate(_: {
35
+ graph: PresetGraph;
36
+ context: ResolvedPresetContext;
37
+ }): Promise<Record<string, Template>>;
38
+ export declare function resolveTemplateFromNode(_: {
39
+ node: PresetNode;
40
+ context: ResolvedPresetContext;
41
+ }): Promise<Record<string, Template>>;
42
+ export declare function resolveScripts(_: {
43
+ graph: PresetGraph;
44
+ context: ResolvedPresetContext<'variable'>;
45
+ }): Promise<Record<string, string>>;
46
+ export declare function resolveScriptsFromNode(_: {
47
+ node: PresetNode;
48
+ context: ResolvedPresetContext<'variable'>;
49
+ }): Promise<Record<string, string>>;
package/lib/content.js CHANGED
@@ -1,141 +1,135 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.customise = customise;
7
- exports.generateContent = generateContent;
8
- exports.getConfigKey = getConfigKey;
9
- exports.getVariable = getVariable;
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveScriptsFromNode = exports.resolveScripts = exports.resolveTemplateFromNode = exports.resolveTemplate = exports.mergeTemplate = exports.resolveVariable = exports.resolveSupplementaryScriptsFromNode = exports.resolveSupplementaryScripts = exports.resolveSupplementaryConfigFromNode = exports.resolveSupplementaryConfig = exports.resolveNoSymlinks = exports.resolveContext = void 0;
4
+ const path_1 = require("path");
5
+ const resolution_1 = require("./resolution");
6
+ const template_1 = require("./template");
7
+ async function resolveContext(_) {
8
+ const { graph } = _;
9
+ const context = Object.assign(Object.assign({}, _.context), { custom: Object.assign(Object.assign({}, _.context.custom), { variable: resolveVariable({ graph, config: _.context.custom }) }) });
10
+ const config = await resolveSupplementaryConfig({ graph, context });
11
+ const noSymlinks = await resolveNoSymlinks({ graph, context });
12
+ const scripts = await resolveSupplementaryScripts({ graph, context });
13
+ return {
14
+ target: context.target,
15
+ custom: Object.assign(Object.assign({}, context.custom), { preset: context.custom.preset, config,
16
+ noSymlinks,
17
+ scripts }),
18
+ };
19
+ }
10
20
  exports.resolveContext = resolveContext;
11
- exports.resolveDynamicMap = resolveDynamicMap;
12
-
13
- var _path = require("path");
14
-
15
- var _io = require("./io");
16
-
17
- var _template = require("./template");
18
-
19
- /*
20
- * *** MIT LICENSE ***
21
- * -------------------------------------------------------------------------
22
- * This code may be modified and distributed under the MIT license.
23
- * See the LICENSE file for details.
24
- * -------------------------------------------------------------------------
25
- *
26
- * @summary Collection of config related helpers
27
- *
28
- * @author Alvis HT Tang <alvis@hilbert.space>
29
- * @license MIT
30
- * @copyright Copyright (c) 2021 - All Rights Reserved.
31
- * -------------------------------------------------------------------------
32
- */
33
-
34
- /**
35
- * customise the template with customisation from .presetterrc
36
- * @param template template configuration
37
- * @param custom content to be merged with the template configuration
38
- * @returns customised configuration
39
- */
40
- function customise(template, custom) {
41
- if (typeof template === 'string' && Array.isArray(custom)) {
42
- return (0, _template.merge)(template.split('\n'), custom).join('\n');
43
- } else if (typeof template === 'object' && !Array.isArray(custom)) {
44
- return (0, _template.merge)(template, custom);
45
- } else {
46
- return template;
47
- }
21
+ async function resolveNoSymlinks(_) {
22
+ var _a;
23
+ const { graph, context } = _;
24
+ const fromPreset = (await Promise.all(graph.map(async (node) => resolveNoSymlinksFromNode({ node, context })))).flat();
25
+ const fromUser = (_a = context.custom.noSymlinks) !== null && _a !== void 0 ? _a : [];
26
+ return [...new Set([...fromPreset, ...fromUser])];
27
+ }
28
+ exports.resolveNoSymlinks = resolveNoSymlinks;
29
+ async function resolveNoSymlinksFromNode(_) {
30
+ var _a;
31
+ const { node, context } = _;
32
+ const { asset, nodes } = node;
33
+ const fromChildren = (await Promise.all(nodes.map(async (extension) => resolveNoSymlinksFromNode({ node: extension, context })))).flat();
34
+ const fromPreset = await (0, resolution_1.loadDynamic)((_a = asset.noSymlinks) !== null && _a !== void 0 ? _a : [], context);
35
+ return [...new Set([...fromChildren, ...fromPreset])];
36
+ }
37
+ async function resolveSupplementaryConfig(_) {
38
+ const { graph, context } = _;
39
+ const fromPresets = (await Promise.all(graph.map(async (node) => resolveSupplementaryConfigFromNode({ node, context })))).reduce((merged, next) => (0, template_1.merge)(merged, next, { mode: 'overwrite' }), {});
40
+ return (0, template_1.merge)(fromPresets, context.custom.config, { mode: 'overwrite' });
41
+ }
42
+ exports.resolveSupplementaryConfig = resolveSupplementaryConfig;
43
+ async function resolveSupplementaryConfigFromNode(_) {
44
+ const { node, context } = _;
45
+ const { asset, nodes } = node;
46
+ const fromChildren = (await Promise.all(nodes.map(async (node) => resolveSupplementaryConfigFromNode({ node, context })))).reduce((merged, next) => (0, template_1.merge)(merged, next, { mode: 'overwrite' }), {});
47
+ const fromPreset = await (0, resolution_1.loadDynamicMap)(asset.supplementaryConfig, context);
48
+ return (0, template_1.merge)(fromChildren, fromPreset, { mode: 'addition' });
49
+ }
50
+ exports.resolveSupplementaryConfigFromNode = resolveSupplementaryConfigFromNode;
51
+ async function resolveSupplementaryScripts(_) {
52
+ const { graph, context } = _;
53
+ const fromPresets = (await Promise.all(graph.map(async (node) => resolveSupplementaryScriptsFromNode({ node, context })))).reduce((merged, next) => (0, template_1.merge)(merged, next, { mode: 'overwrite' }), {});
54
+ return (0, template_1.merge)(fromPresets, context.custom.scripts, { mode: 'overwrite' });
55
+ }
56
+ exports.resolveSupplementaryScripts = resolveSupplementaryScripts;
57
+ async function resolveSupplementaryScriptsFromNode(_) {
58
+ const { node, context } = _;
59
+ const { asset, nodes } = node;
60
+ const { supplementaryScripts } = asset;
61
+ const fromChildren = (await Promise.all(nodes.map(async (node) => resolveSupplementaryScriptsFromNode({ node, context })))).reduce((merged, next) => (0, template_1.merge)(merged, next, { mode: 'overwrite' }), {});
62
+ const fromPreset = await (0, resolution_1.loadDynamic)(supplementaryScripts !== null && supplementaryScripts !== void 0 ? supplementaryScripts : {}, context);
63
+ return (0, template_1.merge)(fromChildren, fromPreset, { mode: 'addition' });
64
+ }
65
+ exports.resolveSupplementaryScriptsFromNode = resolveSupplementaryScriptsFromNode;
66
+ function resolveVariable(_) {
67
+ const { graph, config } = _;
68
+ const fromPresets = graph
69
+ .map((node) => resolveVariableFromNode({ node }))
70
+ .reduce((merged, next) => (0, template_1.merge)(merged, next), {});
71
+ return (0, template_1.merge)(fromPresets, config.variable);
72
+ }
73
+ exports.resolveVariable = resolveVariable;
74
+ function resolveVariableFromNode(_) {
75
+ const { node } = _;
76
+ const { asset, nodes } = node;
77
+ const fromChildren = nodes
78
+ .map((node) => resolveVariableFromNode({ node }))
79
+ .reduce((merged, next) => (0, template_1.merge)(merged, next), {});
80
+ return (0, template_1.merge)(fromChildren, asset.variable);
48
81
  }
49
- /**
50
- * generate configuration content from preset with user customisation
51
- * @param assets list of preset assets
52
- * @param context context about the target project and any customisation in .presetterrc
53
- * @returns a map of configuration content
54
- */
55
-
56
-
57
- async function generateContent(assets, context) {
58
- const resolvedContext = await resolveContext(assets, context);
59
- const resolvedTemplate = await resolveDynamicMap(assets, resolvedContext, 'template'); // merge templates with custom configuration
60
-
61
- const custom = Object.fromEntries(await Promise.all(Object.entries(resolvedTemplate).map(async ([relativePath, templateConfig]) => {
62
- const customConfig = resolvedContext.custom.config[getConfigKey(relativePath)];
63
- return [relativePath, customise(templateConfig, customConfig)];
64
- })));
65
- return (0, _template.template)(custom, resolvedContext.custom.variable);
82
+ function mergeTemplate(current, candidate, options) {
83
+ const resolvedMerge = Object.fromEntries(Object.entries(current).map(([path, template]) => {
84
+ const isIgnoreFile = !(0, path_1.extname)(path) && typeof template === 'string';
85
+ const modeForText = isIgnoreFile ? 'addition' : 'overwrite';
86
+ const mode = typeof template === 'string' ? modeForText : options.mode;
87
+ return [path, (0, template_1.merge)(template, candidate[path], { mode })];
88
+ }));
89
+ return Object.assign(Object.assign({}, candidate), resolvedMerge);
66
90
  }
67
- /**
68
- * compute the corresponding field within the config field of .presetterrc
69
- * @param filename symlink name
70
- * @returns field name in config
71
- */
72
-
73
-
74
- function getConfigKey(filename) {
75
- return (0, _path.basename)(filename, (0, _path.extname)(filename)).replace(/^\./, '').replace(/rc$/, '').replace(/\.config$/, '');
91
+ exports.mergeTemplate = mergeTemplate;
92
+ async function resolveTemplate(_) {
93
+ var _a;
94
+ const { graph, context } = _;
95
+ const fromPreset = (await Promise.all(graph.map(async (node) => resolveTemplateFromNode({ node, context })))).reduce((merged, next) => mergeTemplate(merged, next, { mode: 'overwrite' }), {});
96
+ const merged = Object.fromEntries(Object.entries(fromPreset).map(([path, current]) => {
97
+ const config = context.custom.config[(0, resolution_1.getConfigKey)(path)];
98
+ const candidate = Array.isArray(config) ? config.join('\n') : config;
99
+ const options = { mode: 'addition' };
100
+ return [path, (0, template_1.merge)(current, candidate, options)];
101
+ }));
102
+ const resolvedTemplate = (0, template_1.filter)(merged, ...((_a = context.custom.ignores) !== null && _a !== void 0 ? _a : []));
103
+ return (0, template_1.template)(resolvedTemplate, context.custom.variable);
76
104
  }
77
- /**
78
- * combine the default variables from presets with custom variables
79
- * @param assets list of preset assets
80
- * @param context context about the target project and any customisation in .presetterrc
81
- * @returns combined variables
82
- */
83
-
84
-
85
- function getVariable(assets, context) {
86
- const variables = assets.map(asset => asset.variable).filter(variable => !!variable);
87
- const variableFromPresets = variables.reduce((merged, variable) => (0, _template.merge)(merged, variable), {});
88
- const variableWithCustomConfig = (0, _template.merge)(variableFromPresets, context.custom.variable);
89
- return { ...variableWithCustomConfig
90
- };
105
+ exports.resolveTemplate = resolveTemplate;
106
+ async function resolveTemplateFromNode(_) {
107
+ const { node, context } = _;
108
+ const { asset, nodes } = node;
109
+ const { supplementaryIgnores } = asset;
110
+ const fromChildren = (await Promise.all(nodes.map(async (node) => resolveTemplateFromNode({ node, context })))).reduce((current, next) => mergeTemplate(current, next, { mode: 'overwrite' }), {});
111
+ const fromPreset = await (0, resolution_1.loadDynamicMap)(asset.template, context);
112
+ const merged = mergeTemplate(fromChildren, fromPreset, { mode: 'addition' });
113
+ const ignoreRules = typeof supplementaryIgnores === 'function'
114
+ ? await supplementaryIgnores(context)
115
+ : supplementaryIgnores;
116
+ return (0, template_1.filter)(merged, ...(ignoreRules !== null && ignoreRules !== void 0 ? ignoreRules : []));
91
117
  }
92
- /**
93
- * resolve context values which may be dynamic
94
- * @param assets list of preset assets
95
- * @param context context about the target project and any customisation in .presetterrc
96
- * @returns a context with no further dynamic content
97
- */
98
-
99
-
100
- async function resolveContext(assets, context) {
101
- var _context$custom$noSym;
102
-
103
- const variableContext = { ...context,
104
- custom: { ...context.custom,
105
- variable: getVariable(assets, context)
106
- }
107
- };
108
- const config = (0, _template.merge)(await resolveDynamicMap(assets, variableContext, 'supplementaryConfig'), context.custom.config);
109
- const customList = (_context$custom$noSym = context.custom.noSymlinks) !== null && _context$custom$noSym !== void 0 ? _context$custom$noSym : [];
110
- const assetList = assets.map(async ({
111
- noSymlinks
112
- }) => (0, _io.loadDynamic)(noSymlinks !== null && noSymlinks !== void 0 ? noSymlinks : [], variableContext));
113
- const noSymlinks = [...(await Promise.all(assetList)), ...customList].flat();
114
- return { ...variableContext,
115
- custom: { ...variableContext.custom,
116
- config,
117
- noSymlinks: [...new Set(noSymlinks)]
118
- }
119
- };
118
+ exports.resolveTemplateFromNode = resolveTemplateFromNode;
119
+ async function resolveScripts(_) {
120
+ const { graph, context } = _;
121
+ const fromPresets = (await Promise.all(graph.map(async (node) => resolveScriptsFromNode({ node, context })))).reduce((merged, next) => (0, template_1.merge)(merged, next, { mode: 'overwrite' }), {});
122
+ const fromConfig = context.custom.scripts;
123
+ return (0, template_1.template)((0, template_1.merge)(fromPresets, fromConfig, { mode: 'addition' }), context.custom.variable);
120
124
  }
121
- /**
122
- * resolve a dynamic asset content
123
- * @param assets list of preset assets
124
- * @param context arguments to be passed to the generator function
125
- * @param field field name of PresetAsset to be resolved
126
- * @returns content of the resolved field
127
- */
128
-
129
-
130
- async function resolveDynamicMap(assets, context, field) {
131
- // load templated configuration from presets
132
- const templates = await Promise.all(assets.map(async asset => {
133
- const content = asset[field];
134
- return Object.fromEntries(await Promise.all(Object.entries(content instanceof Function ? await content(context) : { ...content
135
- }).map(async ([relativePath, value]) => [relativePath, // load a file if it's a valid path only
136
- typeof value === 'string' && (0, _path.isAbsolute)(value) ? await (0, _io.loadFile)(value) : await (0, _io.loadDynamic)(value, context)])));
137
- })); // merge all maps
138
-
139
- return templates.reduce((merged, map) => (0, _template.merge)(merged, map), {});
125
+ exports.resolveScripts = resolveScripts;
126
+ async function resolveScriptsFromNode(_) {
127
+ var _a;
128
+ const { node, context } = _;
129
+ const { asset, nodes } = node;
130
+ const fromChildren = (await Promise.all(nodes.map(async (node) => resolveScriptsFromNode({ node, context })))).reduce((merged, next) => (0, template_1.merge)(merged, next, { mode: 'overwrite' }), {});
131
+ const fromPreset = await (0, resolution_1.loadDynamic)((_a = asset.scripts) !== null && _a !== void 0 ? _a : {}, context);
132
+ return (0, template_1.merge)(fromChildren, fromPreset, { mode: 'addition' });
140
133
  }
141
- //# sourceMappingURL=content.js.map
134
+ exports.resolveScriptsFromNode = resolveScriptsFromNode;
135
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NvdXJjZS9jb250ZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQWVBLCtCQUErQjtBQUUvQiw2Q0FBeUU7QUFDekUseUNBQXFEO0FBb0I5QyxLQUFLLFVBQVUsY0FBYyxDQUFDLENBR3BDO0lBQ0MsTUFBTSxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQztJQUdwQixNQUFNLE9BQU8sbUNBQ1IsQ0FBQyxDQUFDLE9BQU8sS0FDWixNQUFNLGtDQUNELENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxLQUNuQixRQUFRLEVBQUUsZUFBZSxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLE1BRWpFLENBQUM7SUFFRixNQUFNLE1BQU0sR0FBRyxNQUFNLDBCQUEwQixDQUFDLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDcEUsTUFBTSxVQUFVLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQy9ELE1BQU0sT0FBTyxHQUFHLE1BQU0sMkJBQTJCLENBQUMsRUFBRSxLQUFLLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUd0RSxPQUFPO1FBQ0wsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1FBQ3RCLE1BQU0sa0NBQ0QsT0FBTyxDQUFDLE1BQU0sS0FDakIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUM3QixNQUFNO1lBQ04sVUFBVTtZQUNWLE9BQU8sR0FDUjtLQUNGLENBQUM7QUFDSixDQUFDO0FBOUJELHdDQThCQztBQVNNLEtBQUssVUFBVSxpQkFBaUIsQ0FBQyxDQUd2Qzs7SUFDQyxNQUFNLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQztJQUU3QixNQUFNLFVBQVUsR0FB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