projen 0.103.26 → 0.103.27
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/.jsii +714 -10
- package/lib/ai-instructions.js +2 -2
- package/lib/awscdk/auto-discover.js +6 -6
- package/lib/awscdk/awscdk-app-java.js +1 -1
- package/lib/awscdk/awscdk-app-py.js +1 -1
- package/lib/awscdk/awscdk-app-ts.js +1 -1
- package/lib/awscdk/awscdk-construct.js +1 -1
- package/lib/awscdk/awscdk-deps-java.js +1 -1
- package/lib/awscdk/awscdk-deps-js.js +1 -1
- package/lib/awscdk/awscdk-deps-py.js +1 -1
- package/lib/awscdk/awscdk-deps.js +1 -1
- package/lib/awscdk/cdk-config.js +3 -3
- package/lib/awscdk/cdk-tasks.js +1 -1
- package/lib/awscdk/integration-test.js +1 -1
- package/lib/awscdk/lambda-extension.js +1 -1
- package/lib/awscdk/lambda-function.js +2 -2
- package/lib/build/build-workflow.js +1 -1
- package/lib/cdk/auto-discover-base.js +2 -2
- package/lib/cdk/construct-lib.js +1 -1
- package/lib/cdk/integration-test-base.js +1 -1
- package/lib/cdk/jsii-build.js +1 -1
- package/lib/cdk/jsii-docgen.js +1 -1
- package/lib/cdk/jsii-project.js +1 -1
- package/lib/cdk8s/auto-discover.js +2 -2
- package/lib/cdk8s/cdk8s-app-py.js +1 -1
- package/lib/cdk8s/cdk8s-app-ts.js +1 -1
- package/lib/cdk8s/cdk8s-construct.js +1 -1
- package/lib/cdk8s/cdk8s-deps-py.js +1 -1
- package/lib/cdk8s/cdk8s-deps.js +1 -1
- package/lib/cdk8s/integration-test.js +1 -1
- package/lib/cdktf/cdktf-construct.js +1 -1
- package/lib/cdktn/cdktn-app-ts.js +1 -1
- package/lib/cdktn/cdktn-config.js +1 -1
- package/lib/cdktn/cdktn-construct.js +1 -1
- package/lib/cdktn/cdktn-deps.js +1 -1
- package/lib/cdktn/cdktn-tasks.js +1 -1
- package/lib/circleci/circleci.js +1 -1
- package/lib/component.js +2 -2
- package/lib/dependencies.js +1 -1
- package/lib/dev-env.js +1 -1
- package/lib/docker-compose/docker-compose-service.js +1 -1
- package/lib/docker-compose/docker-compose.js +1 -1
- package/lib/file.js +1 -1
- package/lib/gitattributes.js +1 -1
- package/lib/github/actions-provider.js +1 -1
- package/lib/github/actions.const.js +1 -1
- package/lib/github/auto-approve.js +1 -1
- package/lib/github/auto-merge.js +1 -1
- package/lib/github/auto-queue.js +1 -1
- package/lib/github/dependabot.js +1 -1
- package/lib/github/dependency-review.js +1 -1
- package/lib/github/github-credentials.js +1 -1
- package/lib/github/github-project.js +1 -1
- package/lib/github/github.js +1 -1
- package/lib/github/merge-queue.js +1 -1
- package/lib/github/mergify.js +1 -1
- package/lib/github/pr-template.js +1 -1
- package/lib/github/pull-request-backport.js +1 -1
- package/lib/github/pull-request-lint.js +1 -1
- package/lib/github/stale.js +1 -1
- package/lib/github/task-workflow-job.js +1 -1
- package/lib/github/task-workflow.js +1 -1
- package/lib/github/workflow-actions.js +1 -1
- package/lib/github/workflow-jobs.js +1 -1
- package/lib/github/workflow-steps.js +1 -1
- package/lib/github/workflows.js +1 -1
- package/lib/gitlab/configuration.js +1 -1
- package/lib/gitlab/gitlab-configuration.js +1 -1
- package/lib/gitlab/nested-configuration.js +1 -1
- package/lib/gitpod.js +1 -1
- package/lib/ignore-file.js +1 -1
- package/lib/ini.js +1 -1
- package/lib/java/java-project.js +1 -1
- package/lib/java/junit.js +1 -1
- package/lib/java/maven-compile.js +1 -1
- package/lib/java/maven-packaging.js +1 -1
- package/lib/java/maven-sample.js +1 -1
- package/lib/java/pom.js +2 -2
- package/lib/java/projenrc.js +1 -1
- package/lib/javascript/biome/biome.js +1 -1
- package/lib/javascript/bundler.js +1 -1
- package/lib/javascript/eslint.js +1 -1
- package/lib/javascript/index.d.ts +1 -0
- package/lib/javascript/index.js +2 -1
- package/lib/javascript/jest.js +4 -4
- package/lib/javascript/license-checker.js +1 -1
- package/lib/javascript/node-config-file.js +18 -4
- package/lib/javascript/node-native-test-runner.d.ts +234 -0
- package/lib/javascript/node-native-test-runner.js +368 -0
- package/lib/javascript/node-package.js +1 -1
- package/lib/javascript/node-project.js +1 -1
- package/lib/javascript/npm-config.js +1 -1
- package/lib/javascript/pnpm-workspace-config.js +2 -2
- package/lib/javascript/pnpm-workspace.js +1 -1
- package/lib/javascript/prettier.js +1 -1
- package/lib/javascript/projenrc.js +1 -1
- package/lib/javascript/typescript-config.js +2 -2
- package/lib/javascript/upgrade-dependencies.js +2 -2
- package/lib/javascript/yarnrc.js +1 -1
- package/lib/json-patch.js +1 -1
- package/lib/json.js +1 -1
- package/lib/license.js +1 -1
- package/lib/logger.js +1 -1
- package/lib/makefile.js +1 -1
- package/lib/object-file.js +1 -1
- package/lib/polaris/coverity-go.js +1 -1
- package/lib/polaris/coverity-java.js +1 -1
- package/lib/polaris/coverity-javascript.js +1 -1
- package/lib/polaris/coverity.js +1 -1
- package/lib/project-build.js +1 -1
- package/lib/project-tree.js +1 -1
- package/lib/project.js +1 -1
- package/lib/projects.js +1 -1
- package/lib/projenrc-json.js +1 -1
- package/lib/projenrc.js +1 -1
- package/lib/properties-file.js +1 -1
- package/lib/python/pip.js +1 -1
- package/lib/python/poetry.js +2 -2
- package/lib/python/projenrc.js +1 -1
- package/lib/python/pyproject-toml-file.js +1 -1
- package/lib/python/pytest-sample.js +1 -1
- package/lib/python/pytest.js +1 -1
- package/lib/python/python-project.js +1 -1
- package/lib/python/python-sample.js +1 -1
- package/lib/python/requirements-file.js +1 -1
- package/lib/python/setuppy.js +1 -1
- package/lib/python/setuptools.js +1 -1
- package/lib/python/uv-config.js +1 -1
- package/lib/python/uv.js +1 -1
- package/lib/python/venv.js +1 -1
- package/lib/readme.js +1 -1
- package/lib/release/publisher.js +1 -1
- package/lib/release/release-trigger.js +1 -1
- package/lib/release/release.js +1 -1
- package/lib/renovatebot.js +1 -1
- package/lib/run-task.cjs +1 -1
- package/lib/sample-file.js +2 -2
- package/lib/script-runner.js +1 -1
- package/lib/sonarqube/javascript.js +1 -1
- package/lib/sonarqube/rust.js +1 -1
- package/lib/sonarqube/sonarqube.js +1 -1
- package/lib/sonarqube/typescript.js +1 -1
- package/lib/source-code.js +1 -1
- package/lib/task-shell.js +1 -1
- package/lib/task.js +1 -1
- package/lib/tasks.js +1 -1
- package/lib/testing.js +1 -1
- package/lib/textfile.js +1 -1
- package/lib/toml.js +1 -1
- package/lib/typescript/projenrc-ts.js +1 -1
- package/lib/typescript/projenrc.js +1 -1
- package/lib/typescript/typescript-runner.js +1 -1
- package/lib/typescript/typescript-typedoc.js +1 -1
- package/lib/typescript/typescript.js +5 -5
- package/lib/version.js +2 -2
- package/lib/vscode/devcontainer.js +1 -1
- package/lib/vscode/extensions.js +1 -1
- package/lib/vscode/launch-config.js +1 -1
- package/lib/vscode/settings.js +1 -1
- package/lib/vscode/vscode.js +1 -1
- package/lib/web/next.js +3 -3
- package/lib/web/postcss.js +1 -1
- package/lib/web/react.js +3 -3
- package/lib/web/tailwind.js +1 -1
- package/lib/xmlfile.js +1 -1
- package/lib/yaml.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import type { IConstruct } from "constructs";
|
|
2
|
+
import { Component } from "../component";
|
|
3
|
+
import type { Project } from "../project";
|
|
4
|
+
import type { NodeConfigSchemaNodeOptions, NodeConfigSchemaTest } from "./node-config";
|
|
5
|
+
import { NodeConfigFile } from "./node-config-file";
|
|
6
|
+
import { NodeProject } from "./node-project";
|
|
7
|
+
/**
|
|
8
|
+
* Whether to update snapshots in task "test" (which is executed in task
|
|
9
|
+
* "build" and build workflows), or create a separate task "test:update" for
|
|
10
|
+
* updating snapshots.
|
|
11
|
+
*/
|
|
12
|
+
export declare enum NodeTestUpdateSnapshot {
|
|
13
|
+
/**
|
|
14
|
+
* Always update snapshots in "test" task.
|
|
15
|
+
*/
|
|
16
|
+
ALWAYS = "always",
|
|
17
|
+
/**
|
|
18
|
+
* Never update snapshots in "test" task and create a separate "test:update" task.
|
|
19
|
+
*/
|
|
20
|
+
NEVER = "never"
|
|
21
|
+
}
|
|
22
|
+
export type ReporterKind = "dot" | "junit" | "lcov" | "spec" | "tap";
|
|
23
|
+
/**
|
|
24
|
+
* Where a reporter's output is written.
|
|
25
|
+
*
|
|
26
|
+
* @see https://nodejs.org/api/test.html#test-reporters
|
|
27
|
+
*/
|
|
28
|
+
export declare class Destination {
|
|
29
|
+
/**
|
|
30
|
+
* The underlying value: `"stdout"`, `"stderr"`, or a file path.
|
|
31
|
+
*/
|
|
32
|
+
readonly value: string;
|
|
33
|
+
/**
|
|
34
|
+
* Write to standard output.
|
|
35
|
+
*/
|
|
36
|
+
static readonly STDOUT: Destination;
|
|
37
|
+
/**
|
|
38
|
+
* Write to standard error.
|
|
39
|
+
*/
|
|
40
|
+
static readonly STDERR: Destination;
|
|
41
|
+
/**
|
|
42
|
+
* Write to a file at the given path.
|
|
43
|
+
* @param path path of the file to write to
|
|
44
|
+
*/
|
|
45
|
+
static file(path: string): Destination;
|
|
46
|
+
private constructor();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A single reporter/destination pair for the Node.js native test runner.
|
|
50
|
+
*
|
|
51
|
+
* @see https://nodejs.org/api/test.html#test-reporters
|
|
52
|
+
*/
|
|
53
|
+
export interface NodeReporter {
|
|
54
|
+
/**
|
|
55
|
+
* The name/kind of the reporter.
|
|
56
|
+
*/
|
|
57
|
+
readonly name: ReporterKind;
|
|
58
|
+
/**
|
|
59
|
+
* Where the reporter's output is written.
|
|
60
|
+
*
|
|
61
|
+
* @see https://github.com/nodejs/node/blob/4215cc35e25c44f9f4fea5a4541afc862db7ef0a/test/parallel/test-runner-reporters.js#L46-L77
|
|
62
|
+
* @default Destination.STDOUT
|
|
63
|
+
*/
|
|
64
|
+
readonly destination: Destination;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Options for Node.js' built-in test runner (`node --test`).
|
|
68
|
+
*/
|
|
69
|
+
export interface NodeNativeTestRunnerOptions {
|
|
70
|
+
/**
|
|
71
|
+
* The directory where coverage files are output, if coverage collection
|
|
72
|
+
* is enabled.
|
|
73
|
+
*
|
|
74
|
+
* @default "coverage"
|
|
75
|
+
*/
|
|
76
|
+
readonly coverageDirectory?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Whether to update snapshots in task "test" (which is executed in task
|
|
79
|
+
* "build" and build workflows), or create a separate task "test:update"
|
|
80
|
+
* for updating snapshots.
|
|
81
|
+
*
|
|
82
|
+
* @default - ALWAYS
|
|
83
|
+
*/
|
|
84
|
+
readonly updateSnapshot?: NodeTestUpdateSnapshot;
|
|
85
|
+
/**
|
|
86
|
+
* Additional options to pass to the `node --test` CLI invocation.
|
|
87
|
+
*
|
|
88
|
+
* Each element is passed as a single argument, exactly as given: no shell
|
|
89
|
+
* parses these, so a flag and its value need separate elements
|
|
90
|
+
* (`["--foo", "bar"]`, not `["--foo bar"]`).
|
|
91
|
+
*
|
|
92
|
+
* @default - no extra options
|
|
93
|
+
*/
|
|
94
|
+
readonly extraCliOptions?: string[];
|
|
95
|
+
/**
|
|
96
|
+
* Preserve the default reporters (`spec`, `lcov`, `junit`) when additional
|
|
97
|
+
* reporters are added.
|
|
98
|
+
*
|
|
99
|
+
* @default true
|
|
100
|
+
*/
|
|
101
|
+
readonly preserveDefaultReporters?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Additional reporters to configure (e.g. `{ name: "tap", destination:
|
|
104
|
+
* Destination.file("test-reports/tap.txt") }`).
|
|
105
|
+
*
|
|
106
|
+
* These are added on top of the default reporters (`spec`, `lcov`, `junit`),
|
|
107
|
+
* which are controlled via `collectCoverage`. Use
|
|
108
|
+
* `NodeNativeTestRunner.addReporter`/`removeReporter`/`listReporters` to
|
|
109
|
+
* manage reporters after construction.
|
|
110
|
+
*
|
|
111
|
+
* @default - no additional reporters
|
|
112
|
+
*/
|
|
113
|
+
readonly reporters?: NodeReporter[];
|
|
114
|
+
/**
|
|
115
|
+
* Path to the JSON configuration file for the test runner.
|
|
116
|
+
*
|
|
117
|
+
* @default "node.config.json"
|
|
118
|
+
*/
|
|
119
|
+
readonly configFilePath?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Glob patterns matching the files that contain tests. By default it
|
|
122
|
+
* combines Node.js' own default test file discovery with Jest conventions.
|
|
123
|
+
*
|
|
124
|
+
* @default - combines Node.js' own default test file discovery with Jest conventions
|
|
125
|
+
*/
|
|
126
|
+
readonly testMatch?: string[];
|
|
127
|
+
/**
|
|
128
|
+
* Indicates whether the coverage information should be collected while
|
|
129
|
+
* executing the test, via `--experimental-test-coverage`.
|
|
130
|
+
*
|
|
131
|
+
* @default true
|
|
132
|
+
*/
|
|
133
|
+
readonly collectCoverage?: boolean;
|
|
134
|
+
/**
|
|
135
|
+
* An array of glob patterns that are matched against all file paths before
|
|
136
|
+
* executing coverage collection. If a file path matches any of the
|
|
137
|
+
* patterns, coverage information will be skipped for it.
|
|
138
|
+
*
|
|
139
|
+
* @default ["**\/test/**", "**\/__tests__/**"]
|
|
140
|
+
*/
|
|
141
|
+
readonly coveragePathIgnorePatterns?: string[];
|
|
142
|
+
/**
|
|
143
|
+
* This option allows the use of a custom global setup module which
|
|
144
|
+
* exports a function that is triggered once before all test suites.
|
|
145
|
+
* Written as `test-global-setup` in the generated Node.js configuration
|
|
146
|
+
* file.
|
|
147
|
+
*
|
|
148
|
+
* @default - undefined
|
|
149
|
+
*/
|
|
150
|
+
readonly globalSetup?: string;
|
|
151
|
+
/**
|
|
152
|
+
* Enable module mocking support via `--experimental-test-module-mocks`.
|
|
153
|
+
*
|
|
154
|
+
* @default false
|
|
155
|
+
*/
|
|
156
|
+
readonly moduleMocks?: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Whether to enable transformation of TypeScript-only syntax (e.g. enums, namespaces).
|
|
159
|
+
*
|
|
160
|
+
* Uses `amaro` (the TypeScript transformer used internally by Node.js) as an
|
|
161
|
+
* external loader via `--import=amaro/transform`. Adds a dependency on the
|
|
162
|
+
* `amaro` package and enables `--enable-source-maps` to preserve accurate
|
|
163
|
+
* stack traces.
|
|
164
|
+
*
|
|
165
|
+
* @see https://github.com/nodejs/amaro
|
|
166
|
+
* @default false
|
|
167
|
+
*/
|
|
168
|
+
readonly transformTypes?: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Additional entries for the `nodeOptions` section of the generated
|
|
171
|
+
* configuration file (e.g. `enableSourceMaps`, `disableWarning`).
|
|
172
|
+
*
|
|
173
|
+
* @default - no additional node options
|
|
174
|
+
*/
|
|
175
|
+
readonly nodeOptions?: NodeConfigSchemaNodeOptions;
|
|
176
|
+
/**
|
|
177
|
+
* Additional entries for the `test` section of the generated
|
|
178
|
+
* configuration file (e.g. `testConcurrency`, `testTimeout`).
|
|
179
|
+
*
|
|
180
|
+
* @default - no additional options
|
|
181
|
+
*/
|
|
182
|
+
readonly testConfig?: NodeConfigSchemaTest;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Configures Node's built-in test runner (`node --test`).
|
|
186
|
+
*
|
|
187
|
+
* Owns the generated Node.js configuration file, the "test", "test:update"
|
|
188
|
+
* and "test:watch" tasks, and the reporters and test match patterns they use.
|
|
189
|
+
*/
|
|
190
|
+
export declare class NodeNativeTestRunner extends Component {
|
|
191
|
+
/**
|
|
192
|
+
* Returns the singleton NodeNativeTestRunner component of a project or undefined
|
|
193
|
+
* if there is none.
|
|
194
|
+
*/
|
|
195
|
+
static of(project: Project): NodeNativeTestRunner | undefined;
|
|
196
|
+
readonly project: NodeProject;
|
|
197
|
+
private readonly coverageDirectory?;
|
|
198
|
+
private readonly updateSnapshot;
|
|
199
|
+
private readonly reporters;
|
|
200
|
+
/**
|
|
201
|
+
* The generated Node.js configuration file.
|
|
202
|
+
*/
|
|
203
|
+
readonly configFile: NodeConfigFile;
|
|
204
|
+
private readonly testReportsDir;
|
|
205
|
+
private readonly testMatch;
|
|
206
|
+
constructor(scope: IConstruct, options?: NodeNativeTestRunnerOptions);
|
|
207
|
+
/**
|
|
208
|
+
* Adds a test match pattern.
|
|
209
|
+
* @param pattern glob pattern to match for tests
|
|
210
|
+
*/
|
|
211
|
+
addTestMatch(pattern: string): void;
|
|
212
|
+
/**
|
|
213
|
+
* Removes a test match pattern, if configured.
|
|
214
|
+
* @param pattern glob pattern to remove
|
|
215
|
+
*/
|
|
216
|
+
removeTestMatch(pattern: string): void;
|
|
217
|
+
/**
|
|
218
|
+
* Adds a reporter, or updates its destination if one with the same name
|
|
219
|
+
* is already configured.
|
|
220
|
+
* @param name The name/kind of the reporter, e.g. `spec`, `junit`, `lcov`.
|
|
221
|
+
* @param destination Where the reporter's output is written.
|
|
222
|
+
* @default Destination.STDOUT
|
|
223
|
+
*/
|
|
224
|
+
addReporter(name: ReporterKind, destination?: Destination): void;
|
|
225
|
+
/**
|
|
226
|
+
* Removes a reporter, if configured.
|
|
227
|
+
* @param name The name/kind of the reporter to remove.
|
|
228
|
+
*/
|
|
229
|
+
removeReporter(name: ReporterKind): void;
|
|
230
|
+
/**
|
|
231
|
+
* Lists the configured reporters, in the order they were added.
|
|
232
|
+
*/
|
|
233
|
+
listReporters(): NodeReporter[];
|
|
234
|
+
}
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NodeNativeTestRunner = exports.Destination = exports.NodeTestUpdateSnapshot = void 0;
|
|
4
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const component_1 = require("../component");
|
|
7
|
+
const node_config_file_1 = require("./node-config-file");
|
|
8
|
+
const node_project_1 = require("./node-project");
|
|
9
|
+
const util_1 = require("../util");
|
|
10
|
+
const constructs_1 = require("../util/constructs");
|
|
11
|
+
const DEFAULT_COVERAGE_DIR = "coverage";
|
|
12
|
+
const DEFAULT_TEST_REPORTS_DIR = "test-reports";
|
|
13
|
+
const DEFAULT_NODE_TEST_MATCH_EXTENSIONS = "cjs,mjs,js,jsx,cts,mts,ts,tsx";
|
|
14
|
+
/**
|
|
15
|
+
* Default glob patterns used to discover test files for Node's built-in test
|
|
16
|
+
* runner, combining Node.js' own default test file discovery with common
|
|
17
|
+
* Jest conventions, so that projects moving from Jest keep matching their
|
|
18
|
+
* existing test files.
|
|
19
|
+
*
|
|
20
|
+
* Node's test runner glob matching follows `glob(7)` and does not support
|
|
21
|
+
* extglobs (e.g. `@(...)`, `+(...)`, `?(...)`), so, unlike Jest's own
|
|
22
|
+
* defaults, each alternative is spelled out explicitly instead of relying on
|
|
23
|
+
* extended glob groups.
|
|
24
|
+
*
|
|
25
|
+
* @see https://nodejs.org/api/test.html#running-tests-from-the-command-line
|
|
26
|
+
*/
|
|
27
|
+
const DEFAULT_NODE_TEST_MATCH = [
|
|
28
|
+
// Node.js' own defaults: files inside a "test" directory, or named/prefixed/suffixed "test"
|
|
29
|
+
`**/test/**/*.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
30
|
+
`**/test.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
31
|
+
`**/test-*.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
32
|
+
`**/*.test.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
33
|
+
`**/*-test.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
34
|
+
`**/*_test.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
35
|
+
// Jest conventions: files inside a "__tests__" directory, or named/suffixed "spec"
|
|
36
|
+
`**/__tests__/**/*.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
37
|
+
`**/spec.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
38
|
+
`**/*.spec.{${DEFAULT_NODE_TEST_MATCH_EXTENSIONS}}`,
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Whether to update snapshots in task "test" (which is executed in task
|
|
42
|
+
* "build" and build workflows), or create a separate task "test:update" for
|
|
43
|
+
* updating snapshots.
|
|
44
|
+
*/
|
|
45
|
+
var NodeTestUpdateSnapshot;
|
|
46
|
+
(function (NodeTestUpdateSnapshot) {
|
|
47
|
+
/**
|
|
48
|
+
* Always update snapshots in "test" task.
|
|
49
|
+
*/
|
|
50
|
+
NodeTestUpdateSnapshot["ALWAYS"] = "always";
|
|
51
|
+
/**
|
|
52
|
+
* Never update snapshots in "test" task and create a separate "test:update" task.
|
|
53
|
+
*/
|
|
54
|
+
NodeTestUpdateSnapshot["NEVER"] = "never";
|
|
55
|
+
})(NodeTestUpdateSnapshot || (exports.NodeTestUpdateSnapshot = NodeTestUpdateSnapshot = {}));
|
|
56
|
+
/**
|
|
57
|
+
* Glob patterns matching the files that contain tests.
|
|
58
|
+
*/
|
|
59
|
+
class TestMatch {
|
|
60
|
+
_patterns = new Set();
|
|
61
|
+
_defaultValue;
|
|
62
|
+
constructor(defaultValue) {
|
|
63
|
+
this._defaultValue = defaultValue;
|
|
64
|
+
}
|
|
65
|
+
add(pattern) {
|
|
66
|
+
this._patterns.add(pattern);
|
|
67
|
+
}
|
|
68
|
+
remove(pattern) {
|
|
69
|
+
this._patterns.delete(pattern);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolved lazily so patterns added or removed after construction are
|
|
73
|
+
* still reflected.
|
|
74
|
+
*/
|
|
75
|
+
deferred() {
|
|
76
|
+
return this._patterns.size > 0
|
|
77
|
+
? Array.from(this._patterns)
|
|
78
|
+
: this._defaultValue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Where a reporter's output is written.
|
|
83
|
+
*
|
|
84
|
+
* @see https://nodejs.org/api/test.html#test-reporters
|
|
85
|
+
*/
|
|
86
|
+
class Destination {
|
|
87
|
+
value;
|
|
88
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.javascript.Destination", version: "0.103.27" };
|
|
89
|
+
/**
|
|
90
|
+
* Write to standard output.
|
|
91
|
+
*/
|
|
92
|
+
static STDOUT = new Destination("stdout");
|
|
93
|
+
/**
|
|
94
|
+
* Write to standard error.
|
|
95
|
+
*/
|
|
96
|
+
static STDERR = new Destination("stderr");
|
|
97
|
+
/**
|
|
98
|
+
* Write to a file at the given path.
|
|
99
|
+
* @param path path of the file to write to
|
|
100
|
+
*/
|
|
101
|
+
static file(path) {
|
|
102
|
+
return new Destination(path);
|
|
103
|
+
}
|
|
104
|
+
constructor(
|
|
105
|
+
/**
|
|
106
|
+
* The underlying value: `"stdout"`, `"stderr"`, or a file path.
|
|
107
|
+
*/
|
|
108
|
+
value) {
|
|
109
|
+
this.value = value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.Destination = Destination;
|
|
113
|
+
/**
|
|
114
|
+
* The set of reporters configured for a `NodeNativeTestRunner`.
|
|
115
|
+
*
|
|
116
|
+
* Provides the `test.testReporter` and `test.testReporterDestination` values
|
|
117
|
+
* of the generated Node.js configuration file.
|
|
118
|
+
*/
|
|
119
|
+
class NodeReporters {
|
|
120
|
+
project;
|
|
121
|
+
_reporters = new Map();
|
|
122
|
+
constructor(project) {
|
|
123
|
+
this.project = project;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Adds a reporter, or updates its destination if one with the same name
|
|
127
|
+
* is already configured.
|
|
128
|
+
* @param name The name/kind of the reporter, e.g. `spec`, `junit`, `lcov`.
|
|
129
|
+
* @param destination Where the reporter's output is written.
|
|
130
|
+
* @default Destination.STDOUT
|
|
131
|
+
*/
|
|
132
|
+
add(name, destination = Destination.STDOUT) {
|
|
133
|
+
this._reporters.set(name, destination);
|
|
134
|
+
if (destination !== Destination.STDOUT &&
|
|
135
|
+
destination !== Destination.STDERR) {
|
|
136
|
+
this.ensureDestinationDirectory(destination);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Removes a reporter, if configured.
|
|
141
|
+
* @param name The name/kind of the reporter to remove.
|
|
142
|
+
*/
|
|
143
|
+
remove(name) {
|
|
144
|
+
this._reporters.delete(name);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Lists the configured reporters, in the order they were added.
|
|
148
|
+
*/
|
|
149
|
+
list() {
|
|
150
|
+
return Array.from(this._reporters, ([name, destination]) => ({
|
|
151
|
+
name,
|
|
152
|
+
destination,
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Ensures the directory of a reporter's file destination exists before the
|
|
157
|
+
* test runner is invoked, and excludes it from the project's `.gitignore`
|
|
158
|
+
* and package (e.g. `.npmignore`) files.
|
|
159
|
+
*/
|
|
160
|
+
ensureDestinationDirectory(destination) {
|
|
161
|
+
const dir = path_1.posix.dirname(destination.value);
|
|
162
|
+
if (dir === ".") {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// the reporter does not create its output directory, so it must exist
|
|
166
|
+
// before the test runner is invoked.
|
|
167
|
+
this.project.testTask.prependExec(`mkdir -p ${dir}`);
|
|
168
|
+
const dirPattern = path_1.posix.join("/", dir, "/");
|
|
169
|
+
this.project.addGitIgnore(dirPattern);
|
|
170
|
+
this.project.addPackageIgnore(dirPattern);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Configures Node's built-in test runner (`node --test`).
|
|
175
|
+
*
|
|
176
|
+
* Owns the generated Node.js configuration file, the "test", "test:update"
|
|
177
|
+
* and "test:watch" tasks, and the reporters and test match patterns they use.
|
|
178
|
+
*/
|
|
179
|
+
class NodeNativeTestRunner extends component_1.Component {
|
|
180
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.javascript.NodeNativeTestRunner", version: "0.103.27" };
|
|
181
|
+
/**
|
|
182
|
+
* Returns the singleton NodeNativeTestRunner component of a project or undefined
|
|
183
|
+
* if there is none.
|
|
184
|
+
*/
|
|
185
|
+
static of(project) {
|
|
186
|
+
const isNodeNativeTestRunner = (c) => c instanceof NodeNativeTestRunner;
|
|
187
|
+
return project.components.find(isNodeNativeTestRunner);
|
|
188
|
+
}
|
|
189
|
+
project;
|
|
190
|
+
coverageDirectory;
|
|
191
|
+
updateSnapshot;
|
|
192
|
+
reporters;
|
|
193
|
+
/**
|
|
194
|
+
* The generated Node.js configuration file.
|
|
195
|
+
*/
|
|
196
|
+
configFile;
|
|
197
|
+
testReportsDir = DEFAULT_TEST_REPORTS_DIR;
|
|
198
|
+
testMatch;
|
|
199
|
+
constructor(scope, options = {}) {
|
|
200
|
+
super(scope);
|
|
201
|
+
this.project = (0, constructs_1.closestProjectMustBe)(scope, node_project_1.NodeProject, new.target.name);
|
|
202
|
+
// Node's snapshot files are generated, not authored.
|
|
203
|
+
this.project.root.annotateGenerated("*.snap");
|
|
204
|
+
this.project.root.annotateGenerated("*.snapshot");
|
|
205
|
+
this.updateSnapshot =
|
|
206
|
+
options.updateSnapshot ?? NodeTestUpdateSnapshot.ALWAYS;
|
|
207
|
+
this.reporters = new NodeReporters(this.project);
|
|
208
|
+
const preserveDefaultReporters = options.preserveDefaultReporters ?? true;
|
|
209
|
+
this.testMatch = new TestMatch(DEFAULT_NODE_TEST_MATCH);
|
|
210
|
+
if (options.testMatch && options.testMatch.length > 0) {
|
|
211
|
+
options.testMatch.forEach((pattern) => this.testMatch.add(pattern));
|
|
212
|
+
}
|
|
213
|
+
const collectCoverage = options.collectCoverage ?? true;
|
|
214
|
+
const coverageDirectory = options.coverageDirectory ?? DEFAULT_COVERAGE_DIR;
|
|
215
|
+
this.coverageDirectory = collectCoverage ? coverageDirectory : undefined;
|
|
216
|
+
if (this.coverageDirectory) {
|
|
217
|
+
const coverageDirectoryPath = path_1.posix.join("/", this.coverageDirectory, "/");
|
|
218
|
+
this.project.addGitIgnore(coverageDirectoryPath);
|
|
219
|
+
this.project.addPackageIgnore(coverageDirectoryPath);
|
|
220
|
+
}
|
|
221
|
+
if (preserveDefaultReporters && collectCoverage) {
|
|
222
|
+
this.reporters.add("spec", Destination.STDOUT);
|
|
223
|
+
this.reporters.add("lcov", Destination.file(`${coverageDirectory}/lcov.info`));
|
|
224
|
+
this.reporters.add("junit", Destination.file(`${this.testReportsDir}/junit.xml`));
|
|
225
|
+
}
|
|
226
|
+
for (const { name, destination } of options.reporters ?? []) {
|
|
227
|
+
this.reporters.add(name, destination);
|
|
228
|
+
}
|
|
229
|
+
const defaultTest = {
|
|
230
|
+
test: true,
|
|
231
|
+
testGlobalSetup: options.globalSetup,
|
|
232
|
+
...(collectCoverage
|
|
233
|
+
? {
|
|
234
|
+
experimentalTestCoverage: true,
|
|
235
|
+
testCoverageExclude: options.coveragePathIgnorePatterns ?? [
|
|
236
|
+
"**/test/**",
|
|
237
|
+
"**/__tests__/**",
|
|
238
|
+
],
|
|
239
|
+
}
|
|
240
|
+
: {}),
|
|
241
|
+
experimentalTestModuleMocks: options.moduleMocks,
|
|
242
|
+
// lazily resolved at synthesis time, so that reporters added or
|
|
243
|
+
// removed via `reporters` after construction are reflected in the
|
|
244
|
+
// generated file.
|
|
245
|
+
testReporter: (() => this.reporters.list().map((r) => r.name)),
|
|
246
|
+
testReporterDestination: (() => this.reporters.list().map((r) => r.destination.value)),
|
|
247
|
+
};
|
|
248
|
+
const test = (0, util_1.deepMerge)([defaultTest, options.testConfig ?? {}], { destructive: true });
|
|
249
|
+
let nodeOptions = { ...options.nodeOptions };
|
|
250
|
+
const extraCliOptions = options.extraCliOptions ?? [];
|
|
251
|
+
if (options.transformTypes ?? false) {
|
|
252
|
+
this.project.addDevDeps("amaro");
|
|
253
|
+
const imports = nodeOptions.import ?? [];
|
|
254
|
+
if (!imports.includes("amaro/transform")) {
|
|
255
|
+
imports.unshift("amaro/transform");
|
|
256
|
+
}
|
|
257
|
+
nodeOptions = {
|
|
258
|
+
...nodeOptions,
|
|
259
|
+
enableSourceMaps: true,
|
|
260
|
+
import: imports,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
this.configFile = new node_config_file_1.NodeConfigFile(this.project, {
|
|
264
|
+
filePath: options.configFilePath,
|
|
265
|
+
test,
|
|
266
|
+
nodeOptions,
|
|
267
|
+
});
|
|
268
|
+
this.project.npmignore?.addPatterns(`/${this.configFile.file.path}`);
|
|
269
|
+
// Test match patterns are positional arguments and must come after every
|
|
270
|
+
// flag: once Node sees the first positional argument it stops parsing
|
|
271
|
+
// flags, so any flag appended after them (e.g. `--watch`) is ignored.
|
|
272
|
+
const command = [
|
|
273
|
+
"node",
|
|
274
|
+
`--experimental-config-file=${this.configFile.file.path}`,
|
|
275
|
+
...extraCliOptions,
|
|
276
|
+
];
|
|
277
|
+
// `testMatch` is a live collection (`add`/`remove` can still be called
|
|
278
|
+
// after construction), so its resolution is deferred with `lazyExecArgs`
|
|
279
|
+
// rather than read eagerly here.
|
|
280
|
+
const testMatchArgs = () => this.testMatch.deferred();
|
|
281
|
+
if (this.updateSnapshot === NodeTestUpdateSnapshot.ALWAYS) {
|
|
282
|
+
this.project.testTask.execArgs(lazyExecArgs(() => [
|
|
283
|
+
...command,
|
|
284
|
+
"--test-update-snapshots",
|
|
285
|
+
...testMatchArgs(),
|
|
286
|
+
]), { receiveArgs: true });
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
const testUpdate = this.project.tasks.tryFind("test:update");
|
|
290
|
+
if (!testUpdate) {
|
|
291
|
+
this.project.addTask("test:update", {
|
|
292
|
+
description: "Update test snapshots",
|
|
293
|
+
execArgs: lazyExecArgs(() => [
|
|
294
|
+
...command,
|
|
295
|
+
"--test-update-snapshots",
|
|
296
|
+
...testMatchArgs(),
|
|
297
|
+
]),
|
|
298
|
+
receiveArgs: true,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
this.project.testTask.execArgs(lazyExecArgs(() => [...command, ...testMatchArgs()]), { receiveArgs: true });
|
|
302
|
+
}
|
|
303
|
+
const testWatch = this.project.tasks.tryFind("test:watch");
|
|
304
|
+
if (!testWatch) {
|
|
305
|
+
this.project.addTask("test:watch", {
|
|
306
|
+
description: "Run tests in watch mode",
|
|
307
|
+
execArgs: lazyExecArgs(() => [
|
|
308
|
+
...command,
|
|
309
|
+
"--watch",
|
|
310
|
+
...testMatchArgs(),
|
|
311
|
+
]),
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Adds a test match pattern.
|
|
317
|
+
* @param pattern glob pattern to match for tests
|
|
318
|
+
*/
|
|
319
|
+
addTestMatch(pattern) {
|
|
320
|
+
this.testMatch.add(pattern);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Removes a test match pattern, if configured.
|
|
324
|
+
* @param pattern glob pattern to remove
|
|
325
|
+
*/
|
|
326
|
+
removeTestMatch(pattern) {
|
|
327
|
+
this.testMatch.remove(pattern);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Adds a reporter, or updates its destination if one with the same name
|
|
331
|
+
* is already configured.
|
|
332
|
+
* @param name The name/kind of the reporter, e.g. `spec`, `junit`, `lcov`.
|
|
333
|
+
* @param destination Where the reporter's output is written.
|
|
334
|
+
* @default Destination.STDOUT
|
|
335
|
+
*/
|
|
336
|
+
addReporter(name, destination) {
|
|
337
|
+
this.reporters.add(name, destination);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Removes a reporter, if configured.
|
|
341
|
+
* @param name The name/kind of the reporter to remove.
|
|
342
|
+
*/
|
|
343
|
+
removeReporter(name) {
|
|
344
|
+
this.reporters.remove(name);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Lists the configured reporters, in the order they were added.
|
|
348
|
+
*/
|
|
349
|
+
listReporters() {
|
|
350
|
+
return this.reporters.list();
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
exports.NodeNativeTestRunner = NodeNativeTestRunner;
|
|
354
|
+
/**
|
|
355
|
+
* Defers resolution of a `TaskStep`'s `execArgs` to synthesis time, when the
|
|
356
|
+
* tasks manifest is rendered.
|
|
357
|
+
*
|
|
358
|
+
* `TaskStep.execArgs` is typed as a plain `string[]`, but the manifest is
|
|
359
|
+
* written through the generic `resolve()` walker (see
|
|
360
|
+
* `ProjenTaskRunner.tasksManifest`) - the same mechanism `JsonFile`/`ObjectFile`
|
|
361
|
+
* use for lazy values elsewhere (e.g. `NodeReporters.list`, `TestMatch`).
|
|
362
|
+
* That walker calls any function it finds, so a callback deferred here runs
|
|
363
|
+
* once, at that point, in place of a plain array.
|
|
364
|
+
*/
|
|
365
|
+
function lazyExecArgs(fn) {
|
|
366
|
+
return fn;
|
|
367
|
+
}
|
|
368
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS1uYXRpdmUtdGVzdC1ydW5uZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvamF2YXNjcmlwdC9ub2RlLW5hdGl2ZS10ZXN0LXJ1bm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsK0JBQTZCO0FBRTdCLDRDQUF5QztBQU16Qyx5REFBb0Q7QUFDcEQsaURBQTZDO0FBQzdDLGtDQUFvQztBQUNwQyxtREFBMEQ7QUFFMUQsTUFBTSxvQkFBb0IsR0FBRyxVQUFVLENBQUM7QUFFeEMsTUFBTSx3QkFBd0IsR0FBRyxjQUFjLENBQUM7QUFFaEQsTUFBTSxrQ0FBa0MsR0FBRywrQkFBK0IsQ0FBQztBQUUzRTs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLHVCQUF1QixHQUFhO0lBQ3hDLDRGQUE0RjtJQUM1RixpQkFBaUIsa0NBQWtDLEdBQUc7SUFDdEQsWUFBWSxrQ0FBa0MsR0FBRztJQUNqRCxjQUFjLGtDQUFrQyxHQUFHO0lBQ25ELGNBQWMsa0NBQWtDLEdBQUc7SUFDbkQsY0FBYyxrQ0FBa0MsR0FBRztJQUNuRCxjQUFjLGtDQUFrQyxHQUFHO0lBQ25ELG1GQUFtRjtJQUNuRixzQkFBc0Isa0NBQWtDLEdBQUc7SUFDM0QsWUFBWSxrQ0FBa0MsR0FBRztJQUNqRCxjQUFjLGtDQUFrQyxHQUFHO0NBQ3BELENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsSUFBWSxzQkFVWDtBQVZELFdBQVksc0JBQXNCO0lBQ2hDOztPQUVHO0lBQ0gsMkNBQWlCLENBQUE7SUFFakI7O09BRUc7SUFDSCx5Q0FBZSxDQUFBO0FBQ2pCLENBQUMsRUFWVyxzQkFBc0Isc0NBQXRCLHNCQUFzQixRQVVqQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxTQUFTO0lBQ0ksU0FBUyxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDOUIsYUFBYSxDQUFXO0lBRXpDLFlBQVksWUFBc0I7UUFDaEMsSUFBSSxDQUFDLGFBQWEsR0FBRyxZQUFZLENBQUM7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IHsgSUNvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tIFwiLi4vY29tcG9uZW50XCI7XG5pbXBvcnQgdHlwZSB7IFByb2plY3QgfSBmcm9tIFwiLi4vcHJvamVjdFwiO1xuaW1wb3J0IHR5cGUge1xuICBOb2RlQ29uZmlnU2NoZW1hTm9kZU9wdGlvbnMsXG4gIE5vZGVDb25maWdTY2hlbWFUZXN0LFxufSBmcm9tIFwiLi9ub2RlLWNvbmZpZ1wiO1xuaW1wb3J0IHsgTm9kZUNvbmZpZ0ZpbGUgfSBmcm9tIFwiLi9ub2RlLWNvbmZpZy1maWxlXCI7XG5pbXBvcnQgeyBOb2RlUHJvamVjdCB9IGZyb20gXCIuL25vZGUtcHJvamVjdFwiO1xuaW1wb3J0IHsgZGVlcE1lcmdlIH0gZnJvbSBcIi4uL3V0aWxcIjtcbmltcG9ydCB7IGNsb3Nlc3RQcm9qZWN0TXVzdEJlIH0gZnJvbSBcIi4uL3V0aWwvY29uc3RydWN0c1wiO1xuXG5jb25zdCBERUZBVUxUX0NPVkVSQUdFX0RJUiA9IFwiY292ZXJhZ2VcIjtcblxuY29uc3QgREVGQVVMVF9URVNUX1JFUE9SVFNfRElSID0gXCJ0ZXN0LXJlcG9ydHNcIjtcblxuY29uc3QgREVGQVVMVF9OT0RFX1RFU1RfTUFUQ0hfRVhURU5TSU9OUyA9IFwiY2pzLG1qcyxqcyxqc3gsY3RzLG10cyx0cyx0c3hcIjtcblxuLyoqXG4gKiBEZWZhdWx0IGdsb2IgcGF0dGVybnMgdXNlZCB0byBkaXNjb3ZlciB0ZXN0IGZpbGVzIGZvciBOb2RlJ3MgYnVpbHQtaW4gdGVzdFxuICogcnVubmVyLCBjb21iaW5pbmcgTm9kZS5qcycgb3duIGRlZmF1bHQgdGVzdCBmaWxlIGRpc2NvdmVyeSB3aXRoIGNvbW1vblxuICogSmVzdCBjb252ZW50aW9ucywgc28gdGhhdCBwcm9qZWN0cyBtb3ZpbmcgZnJvbSBKZXN0IGtlZXAgbWF0Y2hpbmcgdGhlaXJcbiAqIGV4aXN0aW5nIHRlc3QgZmlsZXMuXG4gKlxuICogTm9kZSdzIHRlc3QgcnVubmVyIGdsb2IgbWF0Y2hpbmcgZm9sbG93cyBgZ2xvYig3KWAgYW5kIGRvZXMgbm90IHN1cHBvcnRcbiAqIGV4dGdsb2JzIChlLmcuIGBAKC4uLilgLCBgKyguLi4pYCwgYD8oLi4uKWApLCBzbywgdW5saWtlIEplc3QncyBvd25cbiAqIGRlZmF1bHRzLCBlYWNoIGFsdGVybmF0aXZlIGlzIHNwZWxsZWQgb3V0IGV4cGxpY2l0bHkgaW5zdGVhZCBvZiByZWx5aW5nIG9uXG4gKiBleHRlbmRlZCBnbG9iIGdyb3Vwcy5cbiAqXG4gKiBAc2VlIGh0dHBzOi8vbm9kZWpzLm9yZy9hcGkvdGVzdC5odG1sI3J1bm5pbmctdGVzdHMtZnJvbS10aGUtY29tbWFuZC1saW5lXG4gKi9cbmNvbnN0IERFRkFVTFRfTk9ERV9URVNUX01BVENIOiBzdHJpbmdbXSA9IFtcbiAgLy8gTm9kZS5qcycgb3duIGRlZmF1bHRzOiBmaWxlcyBpbnNpZGUgYSBcInRlc3RcIiBkaXJlY3RvcnksIG9yIG5hbWVkL3ByZWZpeGVkL3N1ZmZpeGVkIFwidGVzdFwiXG4gIGAqKi90ZXN0LyoqLyoueyR7REVGQVVMVF9OT0RFX1RFU1RfTUFUQ0hfRVhURU5TSU9OU319YCxcbiAgYCoqL3Rlc3QueyR7REVGQVVMVF9OT0RFX1RFU1RfTUFUQ0hfRVhURU5TSU9OU319YCxcbiAgYCoqL3Rlc3QtKi57JHtERUZBVUxUX05PREVfVEVTVF9NQVRDSF9FWFRFTlNJT05TfX1gLFxuICBgKiovKi50ZXN0Lnske0RFRkFVTFRfTk9ERV9URVNUX01BVENIX0VYVEVOU0lPTlN9fWAsXG4gIGAqKi8qLXRlc3QueyR7REVGQVVMVF9OT0RFX1RFU1RfTUFUQ0hfRVhURU5TSU9OU319YCxcbiAgYCoqLypfdGVzdC57JHtERUZBVUxUX05PREVfVEVTVF9NQVRDSF9FWFRFTlNJT05TfX1gLFxuICAvLyBKZXN0IGNvbnZlbnRpb25zOiBmaWxlcyBpbnNpZGUgYSBcIl9fdGVzdHNfX1wiIGRpcmVjdG9yeSwgb3IgbmFtZWQvc3VmZml4ZWQgXCJzcGVjXCJcbiAgYCoqL19fdGVzdHNfXy8qKi8qLnske0RFRkFVTFRfTk9ERV9URVNUX01BVENIX0VYVEVOU0lPTlN9fWAsXG4gIGAqKi9zcGVjLnske0RFRkFVTFRfTk9ERV9URVNUX01BVENIX0VYVEVOU0lPTlN9fWAsXG4gIGAqKi8qLnNwZWMueyR7REVGQVVMVF9OT0RFX1RFU1RfTUFUQ0hfRVhURU5TSU9OU319YCxcbl07XG5cbi8qKlxuICogV2hldGhlciB0byB1cGRhdGUgc25hcHNob3RzIGluIHRhc2sgXCJ0ZXN0XCIgKHdoaWNoIGlzIGV4ZWN1dGVkIGluIHRhc2tcbiAqIFwiYnVpbGRcIiBhbmQgYnVpbGQgd29ya2Zsb3dzKSwgb3IgY3JlYXRlIGEgc2VwYXJhdGUgdGFzayBcInRlc3Q6dXBkYXRlXCIgZm9yXG4gKiB1cGRhdGluZyBzbmFwc2hvdHMuXG4gKi9cbmV4cG9ydCBlbnVtIE5vZGVUZXN0VXBkYXRlU25hcHNob3Qge1xuICAvKipcbiAgICogQWx3YXlzIHVwZGF0ZSBzbmFwc2hvdHMgaW4gXCJ0ZXN0XCIgdGFzay5cbiAgICovXG4gIEFMV0FZUyA9IFwiYWx3YXlzXCIsXG5cbiAgLyoqXG4gICAqIE5ldmVyIHVwZGF0ZSBzbmFwc2hvdHMgaW4gXCJ0ZXN0XCIgdGFzayBhbmQgY3JlYXRlIGEgc2VwYXJhdGUgXCJ0ZXN0OnVwZGF0ZVwiIHRhc2suXG4gICAqL1xuICBORVZFUiA9IFwibmV2ZXJcIixcbn1cblxuLyoqXG4gKiBHbG9iIHBhdHRlcm5zIG1hdGNoaW5nIHRoZSBmaWxlcyB0aGF0IGNvbnRhaW4gdGVzdHMuXG4gKi9cbmNsYXNzIFRlc3RNYXRjaCB7XG4gIHByaXZhdGUgcmVhZG9ubHkgX3BhdHRlcm5zID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2RlZmF1bHRWYWx1ZTogc3RyaW5nW107XG5cbiAgY29uc3RydWN0b3IoZGVmYXVsdFZhbHVlOiBzdHJpbmdbXSkge1xuICAgIHRoaXMuX2RlZmF1bHRWYWx1ZSA9IGRlZmF1bHRWYWx1ZTtcbiAgfVxuXG4gIHB1YmxpYyBhZGQocGF0dGVybjogc3RyaW5nKSB7XG4gICAgdGhpcy5fcGF0dGVybnMuYWRkKHBhdHRlcm4pO1xuICB9XG5cbiAgcHVibGljIHJlbW92ZShwYXR0ZXJuOiBzdHJpbmcpIHtcbiAgICB0aGlzLl9wYXR0ZXJucy5kZWxldGUocGF0dGVybik7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZWQgbGF6aWx5IHNvIHBhdHRlcm5zIGFkZGVkIG9yIHJlbW92ZWQgYWZ0ZXIgY29uc3RydWN0aW9uIGFyZVxuICAgKiBzdGlsbCByZWZsZWN0ZWQuXG4gICAqL1xuICBwdWJsaWMgZGVmZXJyZWQoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLl9wYXR0ZXJucy5zaXplID4gMFxuICAgICAgPyBBcnJheS5mcm9tKHRoaXMuX3BhdHRlcm5zKVxuICAgICAgOiB0aGlzLl9kZWZhdWx0VmFsdWU7XG4gIH1cbn1cblxuZXhwb3J0IHR5cGUgUmVwb3J0ZXJLaW5kID0gXCJkb3RcIiB8IFwianVuaXRcIiB8IFwibGNvdlwiIHwgXCJzcGVjXCIgfCBcInRhcFwiO1xuXG4vKipcbiAqIFdoZXJlIGEgcmVwb3J0ZXIncyBvdXRwdXQgaXMgd3JpdHRlbi5cbiAqXG4gKiBAc2VlIGh0dHBzOi8vbm9kZWpzLm9yZy9hcGkvdGVzdC5odG1sI3Rlc3QtcmVwb3J0ZXJzXG4gKi9cbmV4cG9ydCBjbGFzcyBEZXN0aW5hdGlvbiB7XG4gIC8qKlxuICAgKiBXcml0ZSB0byBzdGFuZGFyZCBvdXRwdXQuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IFNURE9VVCA9IG5ldyBEZXN0aW5hdGlvbihcInN0ZG91dFwiKTtcblxuICAvKipcbiAgICogV3JpdGUgdG8gc3RhbmRhcmQgZXJyb3IuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IFNUREVSUiA9IG5ldyBEZXN0aW5hdGlvbihcInN0ZGVyclwiKTtcblxuICAvKipcbiAgICogV3JpdGUgdG8gYSBmaWxlIGF0IHRoZSBnaXZlbiBwYXRoLlxuICAgKiBAcGFyYW0gcGF0aCBwYXRoIG9mIHRoZSBmaWxlIHRvIHdyaXRlIHRvXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGZpbGUocGF0aDogc3RyaW5nKTogRGVzdGluYXRpb24ge1xuICAgIHJldHVybiBuZXcgRGVzdGluYXRpb24ocGF0aCk7XG4gIH1cblxuICBwcml2YXRlIGNvbnN0cnVjdG9yKFxuICAgIC8qKlxuICAgICAqIFRoZSB1bmRlcmx5aW5nIHZhbHVlOiBgXCJzdGRvdXRcImAsIGBcInN0ZGVyclwiYCwgb3IgYSBmaWxlIHBhdGguXG4gICAgICovXG4gICAgcHVibGljIHJlYWRvbmx5IHZhbHVlOiBzdHJpbmcsXG4gICkge31cbn1cblxuLyoqXG4gKiBBIHNpbmdsZSByZXBvcnRlci9kZXN0aW5hdGlvbiBwYWlyIGZvciB0aGUgTm9kZS5qcyBuYXRpdmUgdGVzdCBydW5uZXIuXG4gKlxuICogQHNlZSBodHRwczovL25vZGVqcy5vcmcvYXBpL3Rlc3QuaHRtbCN0ZXN0LXJlcG9ydGVyc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIE5vZGVSZXBvcnRlciB7XG4gIC8qKlxuICAgKiBUaGUgbmFtZS9raW5kIG9mIHRoZSByZXBvcnRlci5cbiAgICovXG4gIHJlYWRvbmx5IG5hbWU6IFJlcG9ydGVyS2luZDtcbiAgLyoqXG4gICAqIFdoZXJlIHRoZSByZXBvcnRlcidzIG91dHB1dCBpcyB3cml0dGVuLlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9ub2RlanMvbm9kZS9ibG9iLzQyMTVjYzM1ZTI1YzQ0ZjlmNGZlYTVhNDU0MWFmYzg2MmRiN2VmMGEvdGVzdC9wYXJhbGxlbC90ZXN0LXJ1bm5lci1yZXBvcnRlcnMuanMjTDQ2LUw3N1xuICAgKiBAZGVmYXVsdCBEZXN0aW5hdGlvbi5TVERPVVRcbiAgICovXG4gIHJlYWRvbmx5IGRlc3RpbmF0aW9uOiBEZXN0aW5hdGlvbjtcbn1cblxuLyoqXG4gKiBUaGUgc2V0IG9mIHJlcG9ydGVycyBjb25maWd1cmVkIGZvciBhIGBOb2RlTmF0aXZlVGVzdFJ1bm5lcmAuXG4gKlxuICogUHJvdmlkZXMgdGhlIGB0ZXN0LnRlc3RSZXBvcnRlcmAgYW5kIGB0ZXN0LnRlc3RSZXBvcnRlckRlc3RpbmF0aW9uYCB2YWx1ZXNcbiAqIG9mIHRoZSBnZW5lcmF0ZWQgTm9kZS5qcyBjb25maWd1cmF0aW9uIGZpbGUuXG4gKi9cbmNsYXNzIE5vZGVSZXBvcnRlcnMge1xuICBwcml2YXRlIHJlYWRvbmx5IF9yZXBvcnRlcnM6IE1hcDxSZXBvcnRlcktpbmQsIERlc3RpbmF0aW9uPiA9IG5ldyBNYXAoKTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHByb2plY3Q6IE5vZGVQcm9qZWN0KSB7fVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgcmVwb3J0ZXIsIG9yIHVwZGF0ZXMgaXRzIGRlc3RpbmF0aW9uIGlmIG9uZSB3aXRoIHRoZSBzYW1lIG5hbWVcbiAgICogaXMgYWxyZWFkeSBjb25maWd1cmVkLlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgbmFtZS9raW5kIG9mIHRoZSByZXBvcnRlciwgZS5nLiBgc3BlY2AsIGBqdW5pdGAsIGBsY292YC5cbiAgICogQHBhcmFtIGRlc3RpbmF0aW9uIFdoZXJlIHRoZSByZXBvcnRlcidzIG91dHB1dCBpcyB3cml0dGVuLlxuICAgKiBAZGVmYXVsdCBEZXN0aW5hdGlvbi5TVERPVVRcbiAgICovXG4gIHB1YmxpYyBhZGQoXG4gICAgbmFtZTogUmVwb3J0ZXJLaW5kLFxuICAgIGRlc3RpbmF0aW9uOiBEZXN0aW5hdGlvbiA9IERlc3RpbmF0aW9uLlNURE9VVCxcbiAgKTogdm9pZCB7XG4gICAgdGhpcy5fcmVwb3J0ZXJzLnNldChuYW1lLCBkZXN0aW5hdGlvbik7XG5cbiAgICBpZiAoXG4gICAgICBkZXN0aW5hdGlvbiAhPT0gRGVzdGluYXRpb24uU1RET1VUICYmXG4gICAgICBkZXN0aW5hdGlvbiAhPT0gRGVzdGluYXRpb24uU1RERVJSXG4gICAgKSB7XG4gICAgICB0aGlzLmVuc3VyZURlc3RpbmF0aW9uRGlyZWN0b3J5KGRlc3RpbmF0aW9uKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlcG9ydGVyLCBpZiBjb25maWd1cmVkLlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgbmFtZS9raW5kIG9mIHRoZSByZXBvcnRlciB0byByZW1vdmUuXG4gICAqL1xuICBwdWJsaWMgcmVtb3ZlKG5hbWU6IFJlcG9ydGVyS2luZCk6IHZvaWQge1xuICAgIHRoaXMuX3JlcG9ydGVycy5kZWxldGUobmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogTGlzdHMgdGhlIGNvbmZpZ3VyZWQgcmVwb3J0ZXJzLCBpbiB0aGUgb3JkZXIgdGhleSB3ZXJlIGFkZGVkLlxuICAgKi9cbiAgcHVibGljIGxpc3QoKTogTm9kZVJlcG9ydGVyW10ge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMuX3JlcG9ydGVycywgKFtuYW1lLCBkZXN0aW5hdGlvbl0pID0+ICh7XG4gICAgICBuYW1lLFxuICAgICAgZGVzdGluYXRpb24sXG4gICAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEVuc3VyZXMgdGhlIGRpcmVjdG9yeSBvZiBhIHJlcG9ydGVyJ3MgZmlsZSBkZXN0aW5hdGlvbiBleGlzdHMgYmVmb3JlIHRoZVxuICAgKiB0ZXN0IHJ1bm5lciBpcyBpbnZva2VkLCBhbmQgZXhjbHVkZXMgaXQgZnJvbSB0aGUgcHJvamVjdCdzIGAuZ2l0aWdub3JlYFxuICAgKiBhbmQgcGFja2FnZSAoZS5nLiBgLm5wbWlnbm9yZWApIGZpbGVzLlxuICAgKi9cbiAgcHJpdmF0ZSBlbnN1cmVEZXN0aW5hdGlvbkRpcmVjdG9yeShkZXN0aW5hdGlvbjogRGVzdGluYXRpb24pOiB2b2lkIHtcbiAgICBjb25zdCBkaXIgPSBwb3NpeC5kaXJuYW1lKGRlc3RpbmF0aW9uLnZhbHVlKTtcbiAgICBpZiAoZGlyID09PSBcIi5cIikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyB0aGUgcmVwb3J0ZXIgZG9lcyBub3QgY3JlYXRlIGl0cyBvdXRwdXQgZGlyZWN0b3J5LCBzbyBpdCBtdXN0IGV4aXN0XG4gICAgLy8gYmVmb3JlIHRoZSB0ZXN0IHJ1bm5lciBpcyBpbnZva2VkLlxuICAgIHRoaXMucHJvamVjdC50ZXN0VGFzay5wcmVwZW5kRXhlYyhgbWtkaXIgLXAgJHtkaXJ9YCk7XG5cbiAgICBjb25zdCBkaXJQYXR0ZXJuID0gcG9zaXguam9pbihcIi9cIiwgZGlyLCBcIi9cIik7XG4gICAgdGhpcy5wcm9qZWN0LmFkZEdpdElnbm9yZShkaXJQYXR0ZXJuKTtcbiAgICB0aGlzLnByb2plY3QuYWRkUGFja2FnZUlnbm9yZShkaXJQYXR0ZXJuKTtcbiAgfVxufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIE5vZGUuanMnIGJ1aWx0LWluIHRlc3QgcnVubmVyIChgbm9kZSAtLXRlc3RgKS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBOb2RlTmF0aXZlVGVzdFJ1bm5lck9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIGRpcmVjdG9yeSB3aGVyZSBjb3ZlcmFnZSBmaWxlcyBhcmUgb3V0cHV0LCBpZiBjb3ZlcmFnZSBjb2xsZWN0aW9uXG4gICAqIGlzIGVuYWJsZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IFwiY292ZXJhZ2VcIlxuICAgKi9cbiAgcmVhZG9ubHkgY292ZXJhZ2VEaXJlY3Rvcnk/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gdXBkYXRlIHNuYXBzaG90cyBpbiB0YXNrIFwidGVzdFwiICh3aGljaCBpcyBleGVjdXRlZCBpbiB0YXNrXG4gICAqIFwiYnVpbGRcIiBhbmQgYnVpbGQgd29ya2Zsb3dzKSwgb3IgY3JlYXRlIGEgc2VwYXJhdGUgdGFzayBcInRlc3Q6dXBkYXRlXCJcbiAgICogZm9yIHVwZGF0aW5nIHNuYXBzaG90cy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBTFdBWVNcbiAgICovXG4gIHJlYWRvbmx5IHVwZGF0ZVNuYXBzaG90PzogTm9kZVRlc3RVcGRhdGVTbmFwc2hvdDtcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBvcHRpb25zIHRvIHBhc3MgdG8gdGhlIGBub2RlIC0tdGVzdGAgQ0xJIGludm9jYXRpb24uXG4gICAqXG4gICAqIEVhY2ggZWxlbWVudCBpcyBwYXNzZWQgYXMgYSBzaW5nbGUgYXJndW1lbnQsIGV4YWN0bHkgYXMgZ2l2ZW46IG5vIHNoZWxsXG4gICAqIHBhcnNlcyB0aGVzZSwgc28gYSBmbGFnIGFuZCBpdHMgdmFsdWUgbmVlZCBzZXBhcmF0ZSBlbGVtZW50c1xuICAgKiAoYFtcIi0tZm9vXCIsIFwiYmFyXCJdYCwgbm90IGBbXCItLWZvbyBiYXJcIl1gKS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBleHRyYSBvcHRpb25zXG4gICAqL1xuICByZWFkb25seSBleHRyYUNsaU9wdGlvbnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogUHJlc2VydmUgdGhlIGRlZmF1bHQgcmVwb3J0ZXJzIChgc3BlY2AsIGBsY292YCwgYGp1bml0YCkgd2hlbiBhZGRpdGlvbmFsXG4gICAqIHJlcG9ydGVycyBhcmUgYWRkZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHByZXNlcnZlRGVmYXVsdFJlcG9ydGVycz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgcmVwb3J0ZXJzIHRvIGNvbmZpZ3VyZSAoZS5nLiBgeyBuYW1lOiBcInRhcFwiLCBkZXN0aW5hdGlvbjpcbiAgICogRGVzdGluYXRpb24uZmlsZShcInRlc3QtcmVwb3J0cy90YXAudHh0XCIpIH1gKS5cbiAgICpcbiAgICogVGhlc2UgYXJlIGFkZGVkIG9uIHRvcCBvZiB0aGUgZGVmYXVsdCByZXBvcnRlcnMgKGBzcGVjYCwgYGxjb3ZgLCBganVuaXRgKSxcbiAgICogd2hpY2ggYXJlIGNvbnRyb2xsZWQgdmlhIGBjb2xsZWN0Q292ZXJhZ2VgLiBVc2VcbiAgICogYE5vZGVOYXRpdmVUZXN0UnVubmVyLmFkZFJlcG9ydGVyYC9gcmVtb3ZlUmVwb3J0ZXJgL2BsaXN0UmVwb3J0ZXJzYCB0b1xuICAgKiBtYW5hZ2UgcmVwb3J0ZXJzIGFmdGVyIGNvbnN0cnVjdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBhZGRpdGlvbmFsIHJlcG9ydGVyc1xuICAgKi9cbiAgcmVhZG9ubHkgcmVwb3J0ZXJzPzogTm9kZVJlcG9ydGVyW107XG5cbiAgLyoqXG4gICAqIFBhdGggdG8gdGhlIEpTT04gY29uZmlndXJhdGlvbiBmaWxlIGZvciB0aGUgdGVzdCBydW5uZXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IFwibm9kZS5jb25maWcuanNvblwiXG4gICAqL1xuICByZWFkb25seSBjb25maWdGaWxlUGF0aD86IHN0cmluZztcblxuICAvKipcbiAgICogR2xvYiBwYXR0ZXJucyBtYXRjaGluZyB0aGUgZmlsZXMgdGhhdCBjb250YWluIHRlc3RzLiBCeSBkZWZhdWx0IGl0XG4gICAqIGNvbWJpbmVzIE5vZGUuanMnIG93biBkZWZhdWx0IHRlc3QgZmlsZSBkaXNjb3Zlcnkgd2l0aCBKZXN0IGNvbnZlbnRpb25zLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGNvbWJpbmVzIE5vZGUuanMnIG93biBkZWZhdWx0IHRlc3QgZmlsZSBkaXNjb3Zlcnkgd2l0aCBKZXN0IGNvbnZlbnRpb25zXG4gICAqL1xuICByZWFkb25seSB0ZXN0TWF0Y2g/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGNvdmVyYWdlIGluZm9ybWF0aW9uIHNob3VsZCBiZSBjb2xsZWN0ZWQgd2hpbGVcbiAgICogZXhlY3V0aW5nIHRoZSB0ZXN0LCB2aWEgYC0tZXhwZXJpbWVudGFsLXRlc3QtY292ZXJhZ2VgLlxuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBjb2xsZWN0Q292ZXJhZ2U/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBbiBhcnJheSBvZiBnbG9iIHBhdHRlcm5zIHRoYXQgYXJlIG1hdGNoZWQgYWdhaW5zdCBhbGwgZmlsZSBwYXRocyBiZWZvcmVcbiAgICogZXhlY3V0aW5nIGNvdmVyYWdlIGNvbGxlY3Rpb24uIElmIGEgZmlsZSBwYXRoIG1hdGNoZXMgYW55IG9mIHRoZVxuICAgKiBwYXR0ZXJucywgY292ZXJhZ2UgaW5mb3JtYXRpb24gd2lsbCBiZSBza2lwcGVkIGZvciBpdC5cbiAgICpcbiAgICogQGRlZmF1bHQgW1wiKipcXC90ZXN0LyoqXCIsIFwiKipcXC9fX3Rlc3RzX18vKipcIl1cbiAgICovXG4gIHJlYWRvbmx5IGNvdmVyYWdlUGF0aElnbm9yZVBhdHRlcm5zPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFRoaXMgb3B0aW9uIGFsbG93cyB0aGUgdXNlIG9mIGEgY3VzdG9tIGdsb2JhbCBzZXR1cCBtb2R1bGUgd2hpY2hcbiAgICogZXhwb3J0cyBhIGZ1bmN0aW9uIHRoYXQgaXMgdHJpZ2dlcmVkIG9uY2UgYmVmb3JlIGFsbCB0ZXN0IHN1aXRlcy5cbiAgICogV3JpdHRlbiBhcyBgdGVzdC1nbG9iYWwtc2V0dXBgIGluIHRoZSBnZW5lcmF0ZWQgTm9kZS5qcyBjb25maWd1cmF0aW9uXG4gICAqIGZpbGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gdW5kZWZpbmVkXG4gICAqL1xuICByZWFkb25seSBnbG9iYWxTZXR1cD86IHN0cmluZztcblxuICAvKipcbiAgICogRW5hYmxlIG1vZHVsZSBtb2NraW5nIHN1cHBvcnQgdmlhIGAtLWV4cGVyaW1lbnRhbC10ZXN0LW1vZHVsZS1tb2Nrc2AuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBtb2R1bGVNb2Nrcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZW5hYmxlIHRyYW5zZm9ybWF0aW9uIG9mIFR5cGVTY3JpcHQtb25seSBzeW50YXggKGUuZy4gZW51bXMsIG5hbWVzcGFjZXMpLlxuICAgKlxuICAgKiBVc2VzIGBhbWFyb2AgKHRoZSBUeXBlU2NyaXB0IHRyYW5zZm9ybWVyIHVzZWQgaW50ZXJuYWxseSBieSBOb2RlLmpzKSBhcyBhblxuICAgKiBleHRlcm5hbCBsb2FkZXIgdmlhIGAtLWltcG9ydD1hbWFyby90cmFuc2Zvcm1gLiBBZGRzIGEgZGVwZW5kZW5jeSBvbiB0aGVcbiAgICogYGFtYXJvYCBwYWNrYWdlIGFuZCBlbmFibGVzIGAtLWVuYWJsZS1zb3VyY2UtbWFwc2AgdG8gcHJlc2VydmUgYWNjdXJhdGVcbiAgICogc3RhY2sgdHJhY2VzLlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9ub2RlanMvYW1hcm9cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHRyYW5zZm9ybVR5cGVzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQWRkaXRpb25hbCBlbnRyaWVzIGZvciB0aGUgYG5vZGVPcHRpb25zYCBzZWN0aW9uIG9mIHRoZSBnZW5lcmF0ZWRcbiAgICogY29uZmlndXJhdGlvbiBmaWxlIChlLmcuIGBlbmFibGVTb3VyY2VNYXBzYCwgYGRpc2FibGVXYXJuaW5nYCkuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gYWRkaXRpb25hbCBub2RlIG9wdGlvbnNcbiAgICovXG4gIHJlYWRvbmx5IG5vZGVPcHRpb25zPzogTm9kZUNvbmZpZ1NjaGVtYU5vZGVPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBBZGRpdGlvbmFsIGVudHJpZXMgZm9yIHRoZSBgdGVzdGAgc2VjdGlvbiBvZiB0aGUgZ2VuZXJhdGVkXG4gICAqIGNvbmZpZ3VyYXRpb24gZmlsZSAoZS5nLiBgdGVzdENvbmN1cnJlbmN5YCwgYHRlc3RUaW1lb3V0YCkuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gYWRkaXRpb25hbCBvcHRpb25zXG4gICAqL1xuICByZWFkb25seSB0ZXN0Q29uZmlnPzogTm9kZUNvbmZpZ1NjaGVtYVRlc3Q7XG59XG5cbi8qKlxuICogQ29uZmlndXJlcyBOb2RlJ3MgYnVpbHQtaW4gdGVzdCBydW5uZXIgKGBub2RlIC0tdGVzdGApLlxuICpcbiAqIE93bnMgdGhlIGdlbmVyYXRlZCBOb2RlLmpzIGNvbmZpZ3VyYXRpb24gZmlsZSwgdGhlIFwidGVzdFwiLCBcInRlc3Q6dXBkYXRlXCJcbiAqIGFuZCBcInRlc3Q6d2F0Y2hcIiB0YXNrcywgYW5kIHRoZSByZXBvcnRlcnMgYW5kIHRlc3QgbWF0Y2ggcGF0dGVybnMgdGhleSB1c2UuXG4gKi9cbmV4cG9ydCBjbGFzcyBOb2RlTmF0aXZlVGVzdFJ1bm5lciBleHRlbmRzIENvbXBvbmVudCB7XG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBzaW5nbGV0b24gTm9kZU5hdGl2ZVRlc3RSdW5uZXIgY29tcG9uZW50IG9mIGEgcHJvamVjdCBvciB1bmRlZmluZWRcbiAgICogaWYgdGhlcmUgaXMgbm9uZS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgb2YocHJvamVjdDogUHJvamVjdCk6IE5vZGVOYXRpdmVUZXN0UnVubmVyIHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBpc05vZGVOYXRpdmVUZXN0UnVubmVyID0gKGM6IENvbXBvbmVudCk6IGMgaXMgTm9kZU5hdGl2ZVRlc3RSdW5uZXIgPT5cbiAgICAgIGMgaW5zdGFuY2VvZiBOb2RlTmF0aXZlVGVzdFJ1bm5lcjtcbiAgICByZXR1cm4gcHJvamVjdC5jb21wb25lbnRzLmZpbmQoaXNOb2RlTmF0aXZlVGVzdFJ1bm5lcik7XG4gIH1cblxuICBwdWJsaWMgcmVhZG9ubHkgcHJvamVjdDogTm9kZVByb2plY3Q7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBjb3ZlcmFnZURpcmVjdG9yeT86IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IHVwZGF0ZVNuYXBzaG90OiBOb2RlVGVzdFVwZGF0ZVNuYXBzaG90O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcmVwb3J0ZXJzOiBOb2RlUmVwb3J0ZXJzO1xuXG4gIC8qKlxuICAgKiBUaGUgZ2VuZXJhdGVkIE5vZGUuanMgY29uZmlndXJhdGlvbiBmaWxlLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNvbmZpZ0ZpbGU6IE5vZGVDb25maWdGaWxlO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgdGVzdFJlcG9ydHNEaXI6IHN0cmluZyA9IERFRkFVTFRfVEVTVF9SRVBPUlRTX0RJUjtcblxuICBwcml2YXRlIHJlYWRvbmx5IHRlc3RNYXRjaDogVGVzdE1hdGNoO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBJQ29uc3RydWN0LCBvcHRpb25zOiBOb2RlTmF0aXZlVGVzdFJ1bm5lck9wdGlvbnMgPSB7fSkge1xuICAgIHN1cGVyKHNjb3BlKTtcbiAgICB0aGlzLnByb2plY3QgPSBjbG9zZXN0UHJvamVjdE11c3RCZShzY29wZSwgTm9kZVByb2plY3QsIG5ldy50YXJnZXQubmFtZSk7XG5cbiAgICAvLyBOb2RlJ3Mgc25hcHNob3QgZmlsZXMgYXJlIGdlbmVyYXRlZCwgbm90IGF1dGhvcmVkLlxuICAgIHRoaXMucHJvamVjdC5yb290LmFubm90YXRlR2VuZXJhdGVkKFwiKi5zbmFwXCIpO1xuICAgIHRoaXMucHJvamVjdC5yb290LmFubm90YXRlR2VuZXJhdGVkKFwiKi5zbmFwc2hvdFwiKTtcblxuICAgIHRoaXMudXBkYXRlU25hcHNob3QgPVxuICAgICAgb3B0aW9ucy51cGRhdGVTbmFwc2hvdCA/PyBOb2RlVGVzdFVwZGF0ZVNuYXBzaG90LkFMV0FZUztcblxuICAgIHRoaXMucmVwb3J0ZXJzID0gbmV3IE5vZGVSZXBvcnRlcnModGhpcy5wcm9qZWN0KTtcbiAgICBjb25zdCBwcmVzZXJ2ZURlZmF1bHRSZXBvcnRlcnMgPSBvcHRpb25zLnByZXNlcnZlRGVmYXVsdFJlcG9ydGVycyA/PyB0cnVlO1xuXG4gICAgdGhpcy50ZXN0TWF0Y2ggPSBuZXcgVGVzdE1hdGNoKERFRkFVTFRfTk9ERV9URVNUX01BVENIKTtcblxuICAgIGlmIChvcHRpb25zLnRlc3RNYXRjaCAmJiBvcHRpb25zLnRlc3RNYXRjaC5sZW5ndGggPiAwKSB7XG4gICAgICBvcHRpb25zLnRlc3RNYXRjaC5mb3JFYWNoKChwYXR0ZXJuKSA9PiB0aGlzLnRlc3RNYXRjaC5hZGQocGF0dGVybikpO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbGxlY3RDb3ZlcmFnZSA9IG9wdGlvbnMuY29sbGVjdENvdmVyYWdlID8/IHRydWU7XG4gICAgY29uc3QgY292ZXJhZ2VEaXJlY3RvcnkgPSBvcHRpb25zLmNvdmVyYWdlRGlyZWN0b3J5ID8/IERFRkFVTFRfQ09WRVJBR0VfRElSO1xuICAgIHRoaXMuY292ZXJhZ2VEaXJlY3RvcnkgPSBjb2xsZWN0Q292ZXJhZ2UgPyBjb3ZlcmFnZURpcmVjdG9yeSA6IHVuZGVmaW5lZDtcblxuICAgIGlmICh0aGlzLmNvdmVyYWdlRGlyZWN0b3J5KSB7XG4gICAgICBjb25zdCBjb3ZlcmFnZURpcmVjdG9yeVBhdGggPSBwb3NpeC5qb2luKFxuICAgICAgICBcIi9cIixcbiAgICAgICAgdGhpcy5jb3ZlcmFnZURpcmVjdG9yeSxcbiAgICAgICAgXCIvXCIsXG4gICAgICApO1xuICAgICAgdGhpcy5wcm9qZWN0LmFkZEdpdElnbm9yZShjb3ZlcmFnZURpcmVjdG9yeVBhdGgpO1xuICAgICAgdGhpcy5wcm9qZWN0LmFkZFBhY2thZ2VJZ25vcmUoY292ZXJhZ2VEaXJlY3RvcnlQYXRoKTtcbiAgICB9XG5cbiAgICBpZiAocHJlc2VydmVEZWZhdWx0UmVwb3J0ZXJzICYmIGNvbGxlY3RDb3ZlcmFnZSkge1xuICAgICAgdGhpcy5yZXBvcnRlcnMuYWRkKFwic3BlY1wiLCBEZXN0aW5hdGlvbi5TVERPVVQpO1xuICAgICAgdGhpcy5yZXBvcnRlcnMuYWRkKFxuICAgICAgICBcImxjb3ZcIixcbiAgICAgICAgRGVzdGluYXRpb24uZmlsZShgJHtjb3ZlcmFnZURpcmVjdG9yeX0vbGNvdi5pbmZvYCksXG4gICAgICApO1xuICAgICAgdGhpcy5yZXBvcnRlcnMuYWRkKFxuICAgICAgICBcImp1bml0XCIsXG4gICAgICAgIERlc3RpbmF0aW9uLmZpbGUoYCR7dGhpcy50ZXN0UmVwb3J0c0Rpcn0vanVuaXQueG1sYCksXG4gICAgICApO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgeyBuYW1lLCBkZXN0aW5hdGlvbiB9IG9mIG9wdGlvbnMucmVwb3J0ZXJzID8/IFtdKSB7XG4gICAgICB0aGlzLnJlcG9ydGVycy5hZGQobmFtZSwgZGVzdGluYXRpb24pO1xuICAgIH1cblxuICAgIGNvbnN0IGRlZmF1bHRUZXN0OiBOb2RlQ29uZmlnU2NoZW1hVGVzdCA9IHtcbiAgICAgIHRlc3Q6IHRydWUsXG4gICAgICB0ZXN0R2xvYmFsU2V0dXA6IG9wdGlvbnMuZ2xvYmFsU2V0dXAsXG4gICAgICAuLi4oY29sbGVjdENvdmVyYWdlXG4gICAgICAgID8ge1xuICAgICAgICAgICAgZXhwZXJpbWVudGFsVGVzdENvdmVyYWdlOiB0cnVlLFxuICAgICAgICAgICAgdGVzdENvdmVyYWdlRXhjbHVkZTogb3B0aW9ucy5jb3ZlcmFnZVBhdGhJZ25vcmVQYXR0ZXJucyA/PyBbXG4gICAgICAgICAgICAgIFwiKiovdGVzdC8qKlwiLFxuICAgICAgICAgICAgICBcIioqL19fdGVzdHNfXy8qKlwiLFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9XG4gICAgICAgIDoge30pLFxuICAgICAgZXhwZXJpbWVudGFsVGVzdE1vZHVsZU1vY2tzOiBvcHRpb25zLm1vZHVsZU1vY2tzLFxuICAgICAgLy8gbGF6aWx5IHJlc29sdmVkIGF0IHN5bnRoZXNpcyB0aW1lLCBzbyB0aGF0IHJlcG9ydGVycyBhZGRlZCBvclxuICAgICAgLy8gcmVtb3ZlZCB2aWEgYHJlcG9ydGVyc2AgYWZ0ZXIgY29uc3RydWN0aW9uIGFyZSByZWZsZWN0ZWQgaW4gdGhlXG4gICAgICAvLyBnZW5lcmF0ZWQgZmlsZS5cbiAgICAgIHRlc3RSZXBvcnRlcjogKCgpID0+IHRoaXMucmVwb3J0ZXJzLmxpc3QoKS5tYXAoKHIpID0+IHIubmFtZSkpIGFzIGFueSxcbiAgICAgIHRlc3RSZXBvcnRlckRlc3RpbmF0aW9uOiAoKCkgPT5cbiAgICAgICAgdGhpcy5yZXBvcnRlcnMubGlzdCgpLm1hcCgocikgPT4gci5kZXN0aW5hdGlvbi52YWx1ZSkpIGFzIGFueSxcbiAgICB9O1xuICAgIGNvbnN0IHRlc3Q6IE5vZGVDb25maWdTY2hlbWFUZXN0ID0gZGVlcE1lcmdlKFxuICAgICAgW2RlZmF1bHRUZXN0LCBvcHRpb25zLnRlc3RDb25maWcgPz8ge31dLFxuICAgICAgeyBkZXN0cnVjdGl2ZTogdHJ1ZSB9LFxuICAgICk7XG5cbiAgICBsZXQgbm9kZU9wdGlvbnM6IE5vZGVDb25maWdTY2hlbWFOb2RlT3B0aW9ucyA9IHsgLi4ub3B0aW9ucy5ub2RlT3B0aW9ucyB9O1xuICAgIGNvbnN0IGV4dHJhQ2xpT3B0aW9ucyA9IG9wdGlvbnMuZXh0cmFDbGlPcHRpb25zID8/IFtdO1xuXG4gICAgaWYgKG9wdGlvbnMudHJhbnNmb3JtVHlwZXMgPz8gZmFsc2UpIHtcbiAgICAgIHRoaXMucHJvamVjdC5hZGREZXZEZXBzKFwiYW1hcm9cIik7XG4gICAgICBjb25zdCBpbXBvcnRzID0gbm9kZU9wdGlvbnMuaW1wb3J0ID8/IFtdO1xuICAgICAgaWYgKCFpbXBvcnRzLmluY2x1ZGVzKFwiYW1hcm8vdHJhbnNmb3JtXCIpKSB7XG4gICAgICAgIGltcG9ydHMudW5zaGlmdChcImFtYXJvL3RyYW5zZm9ybVwiKTtcbiAgICAgIH1cbiAgICAgIG5vZGVPcHRpb25zID0ge1xuICAgICAgICAuLi5ub2RlT3B0aW9ucyxcbiAgICAgICAgZW5hYmxlU291cmNlTWFwczogdHJ1ZSxcbiAgICAgICAgaW1wb3J0OiBpbXBvcnRzLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICB0aGlzLmNvbmZpZ0ZpbGUgPSBuZXcgTm9kZUNvbmZpZ0ZpbGUodGhpcy5wcm9qZWN0LCB7XG4gICAgICBmaWxlUGF0aDogb3B0aW9ucy5jb25maWdGaWxlUGF0aCxcbiAgICAgIHRlc3QsXG4gICAgICBub2RlT3B0aW9ucyxcbiAgICB9KTtcbiAgICB0aGlzLnByb2plY3QubnBtaWdub3JlPy5hZGRQYXR0ZXJucyhgLyR7dGhpcy5jb25maWdGaWxlLmZpbGUucGF0aH1gKTtcblxuICAgIC8vIFRlc3QgbWF0Y2ggcGF0dGVybnMgYXJlIHBvc2l0aW9uYWwgYXJndW1lbnRzIGFuZCBtdXN0IGNvbWUgYWZ0ZXIgZXZlcnlcbiAgICAvLyBmbGFnOiBvbmNlIE5vZGUgc2VlcyB0aGUgZmlyc3QgcG9zaXRpb25hbCBhcmd1bWVudCBpdCBzdG9wcyBwYXJzaW5nXG4gICAgLy8gZmxhZ3MsIHNvIGFueSBmbGFnIGFwcGVuZGVkIGFmdGVyIHRoZW0gKGUuZy4gYC0td2F0Y2hgKSBpcyBpZ25vcmVkLlxuICAgIGNvbnN0IGNvbW1hbmQ6IHN0cmluZ1tdID0gW1xuICAgICAgXCJub2RlXCIsXG4gICAgICBgLS1leHBlcmltZW50YWwtY29uZmlnLWZpbGU9JHt0aGlzLmNvbmZpZ0ZpbGUuZmlsZS5wYXRofWAsXG4gICAgICAuLi5leHRyYUNsaU9wdGlvbnMsXG4gICAgXTtcblxuICAgIC8vIGB0ZXN0TWF0Y2hgIGlzIGEgbGl2ZSBjb2xsZWN0aW9uIChgYWRkYC9gcmVtb3ZlYCBjYW4gc3RpbGwgYmUgY2FsbGVkXG4gICAgLy8gYWZ0ZXIgY29uc3RydWN0aW9uKSwgc28gaXRzIHJlc29sdXRpb24gaXMgZGVmZXJyZWQgd2l0aCBgbGF6eUV4ZWNBcmdzYFxuICAgIC8vIHJhdGhlciB0aGFuIHJlYWQgZWFnZXJseSBoZXJlLlxuICAgIGNvbnN0IHRlc3RNYXRjaEFyZ3MgPSAoKSA9PiB0aGlzLnRlc3RNYXRjaC5kZWZlcnJlZCgpO1xuXG4gICAgaWYgKHRoaXMudXBkYXRlU25hcHNob3QgPT09IE5vZGVUZXN0VXBkYXRlU25hcHNob3QuQUxXQVlTKSB7XG4gICAgICB0aGlzLnByb2plY3QudGVzdFRhc2suZXhlY0FyZ3MoXG4gICAgICAgIGxhenlFeGVjQXJncygoKSA9PiBbXG4gICAgICAgICAgLi4uY29tbWFuZCxcbiAgICAgICAgICBcIi0tdGVzdC11cGRhdGUtc25hcHNob3RzXCIsXG4gICAgICAgICAgLi4udGVzdE1hdGNoQXJncygpLFxuICAgICAgICBdKSxcbiAgICAgICAgeyByZWNlaXZlQXJnczogdHJ1ZSB9LFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgdGVzdFVwZGF0ZSA9IHRoaXMucHJvamVjdC50YXNrcy50cnlGaW5kKFwidGVzdDp1cGRhdGVcIik7XG4gICAgICBpZiAoIXRlc3RVcGRhdGUpIHtcbiAgICAgICAgdGhpcy5wcm9qZWN0LmFkZFRhc2soXCJ0ZXN0OnVwZGF0ZVwiLCB7XG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiVXBkYXRlIHRlc3Qgc25hcHNob3RzXCIsXG4gICAgICAgICAgZXhlY0FyZ3M6IGxhenlFeGVjQXJncygoKSA9PiBbXG4gICAgICAgICAgICAuLi5jb21tYW5kLFxuICAgICAgICAgICAgXCItLXRlc3QtdXBkYXRlLXNuYXBzaG90c1wiLFxuICAgICAgICAgICAgLi4udGVzdE1hdGNoQXJncygpLFxuICAgICAgICAgIF0pLFxuICAgICAgICAgIHJlY2VpdmVBcmdzOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5wcm9qZWN0LnRlc3RUYXNrLmV4ZWNBcmdzKFxuICAgICAgICBsYXp5RXhlY0FyZ3MoKCkgPT4gWy4uLmNvbW1hbmQsIC4uLnRlc3RNYXRjaEFyZ3MoKV0pLFxuICAgICAgICB7IHJlY2VpdmVBcmdzOiB0cnVlIH0sXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHRlc3RXYXRjaCA9IHRoaXMucHJvamVjdC50YXNrcy50cnlGaW5kKFwidGVzdDp3YXRjaFwiKTtcbiAgICBpZiAoIXRlc3RXYXRjaCkge1xuICAgICAgdGhpcy5wcm9qZWN0LmFkZFRhc2soXCJ0ZXN0OndhdGNoXCIsIHtcbiAgICAgICAgZGVzY3JpcHRpb246IFwiUnVuIHRlc3RzIGluIHdhdGNoIG1vZGVcIixcbiAgICAgICAgZXhlY0FyZ3M6IGxhenlFeGVjQXJncygoKSA9PiBbXG4gICAgICAgICAgLi4uY29tbWFuZCxcbiAgICAgICAgICBcIi0td2F0Y2hcIixcbiAgICAgICAgICAuLi50ZXN0TWF0Y2hBcmdzKCksXG4gICAgICAgIF0pLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSB0ZXN0IG1hdGNoIHBhdHRlcm4uXG4gICAqIEBwYXJhbSBwYXR0ZXJuIGdsb2IgcGF0dGVybiB0byBtYXRjaCBmb3IgdGVzdHNcbiAgICovXG4gIHB1YmxpYyBhZGRUZXN0TWF0Y2gocGF0dGVybjogc3RyaW5nKSB7XG4gICAgdGhpcy50ZXN0TWF0Y2guYWRkKHBhdHRlcm4pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYSB0ZXN0IG1hdGNoIHBhdHRlcm4sIGlmIGNvbmZpZ3VyZWQuXG4gICAqIEBwYXJhbSBwYXR0ZXJuIGdsb2IgcGF0dGVybiB0byByZW1vdmVcbiAgICovXG4gIHB1YmxpYyByZW1vdmVUZXN0TWF0Y2gocGF0dGVybjogc3RyaW5nKSB7XG4gICAgdGhpcy50ZXN0TWF0Y2gucmVtb3ZlKHBhdHRlcm4pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSByZXBvcnRlciwgb3IgdXBkYXRlcyBpdHMgZGVzdGluYXRpb24gaWYgb25lIHdpdGggdGhlIHNhbWUgbmFtZVxuICAgKiBpcyBhbHJlYWR5IGNvbmZpZ3VyZWQuXG4gICAqIEBwYXJhbSBuYW1lIFRoZSBuYW1lL2tpbmQgb2YgdGhlIHJlcG9ydGVyLCBlLmcuIGBzcGVjYCwgYGp1bml0YCwgYGxjb3ZgLlxuICAgKiBAcGFyYW0gZGVzdGluYXRpb24gV2hlcmUgdGhlIHJlcG9ydGVyJ3Mgb3V0cHV0IGlzIHdyaXR0ZW4uXG4gICAqIEBkZWZhdWx0IERlc3RpbmF0aW9uLlNURE9VVFxuICAgKi9cbiAgcHVibGljIGFkZFJlcG9ydGVyKG5hbWU6IFJlcG9ydGVyS2luZCwgZGVzdGluYXRpb24/OiBEZXN0aW5hdGlvbikge1xuICAgIHRoaXMucmVwb3J0ZXJzLmFkZChuYW1lLCBkZXN0aW5hdGlvbik7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlcG9ydGVyLCBpZiBjb25maWd1cmVkLlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgbmFtZS9raW5kIG9mIHRoZSByZXBvcnRlciB0byByZW1vdmUuXG4gICAqL1xuICBwdWJsaWMgcmVtb3ZlUmVwb3J0ZXIobmFtZTogUmVwb3J0ZXJLaW5kKSB7XG4gICAgdGhpcy5yZXBvcnRlcnMucmVtb3ZlKG5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3RzIHRoZSBjb25maWd1cmVkIHJlcG9ydGVycywgaW4gdGhlIG9yZGVyIHRoZXkgd2VyZSBhZGRlZC5cbiAgICovXG4gIHB1YmxpYyBsaXN0UmVwb3J0ZXJzKCk6IE5vZGVSZXBvcnRlcltdIHtcbiAgICByZXR1cm4gdGhpcy5yZXBvcnRlcnMubGlzdCgpO1xuICB9XG59XG5cbi8qKlxuICogRGVmZXJzIHJlc29sdXRpb24gb2YgYSBgVGFza1N0ZXBgJ3MgYGV4ZWNBcmdzYCB0byBzeW50aGVzaXMgdGltZSwgd2hlbiB0aGVcbiAqIHRhc2tzIG1hbmlmZXN0IGlzIHJlbmRlcmVkLlxuICpcbiAqIGBUYXNrU3RlcC5leGVjQXJnc2AgaXMgdHlwZWQgYXMgYSBwbGFpbiBgc3RyaW5nW11gLCBidXQgdGhlIG1hbmlmZXN0IGlzXG4gKiB3cml0dGVuIHRocm91Z2ggdGhlIGdlbmVyaWMgYHJlc29sdmUoKWAgd2Fsa2VyIChzZWVcbiAqIGBQcm9qZW5UYXNrUnVubmVyLnRhc2tzTWFuaWZlc3RgKSAtIHRoZSBzYW1lIG1lY2hhbmlzbSBgSnNvbkZpbGVgL2BPYmplY3RGaWxlYFxuICogdXNlIGZvciBsYXp5IHZhbHVlcyBlbHNld2hlcmUgKGUuZy4gYE5vZGVSZXBvcnRlcnMubGlzdGAsIGBUZXN0TWF0Y2hgKS5cbiAqIFRoYXQgd2Fsa2VyIGNhbGxzIGFueSBmdW5jdGlvbiBpdCBmaW5kcywgc28gYSBjYWxsYmFjayBkZWZlcnJlZCBoZXJlIHJ1bnNcbiAqIG9uY2UsIGF0IHRoYXQgcG9pbnQsIGluIHBsYWNlIG9mIGEgcGxhaW4gYXJyYXkuXG4gKi9cbmZ1bmN0aW9uIGxhenlFeGVjQXJncyhmbjogKCkgPT4gc3RyaW5nW10pOiBzdHJpbmdbXSB7XG4gIHJldHVybiBmbiBhcyBhbnk7XG59XG4iXX0=
|