UNPKG

@napi-rs/cli

Version:

Cli tools for napi-rs

1,016 lines (1,015 loc) 103 kB
import { Cli, Command } from "clipanion"; //#region src/def/artifacts.d.ts declare abstract class BaseArtifactsCommand extends Command { static paths: string[][]; static usage: import("clipanion").Usage; cwd: string; configPath?: string; packageJsonPath: string; outputDir: string; npmDir: string; buildOutputDir?: string; getOptions(): { cwd: string; configPath: string | undefined; packageJsonPath: string; outputDir: string; npmDir: string; buildOutputDir: string | undefined; }; } /** * Copy artifacts from Github Actions into npm packages and ready to publish */ interface ArtifactsOptions { /** * The working directory of where napi command will be executed in, all other paths options are relative to this path * * @default process.cwd() */ cwd?: string; /** * Path to `napi` config json file */ configPath?: string; /** * Path to `package.json` * * @default 'package.json' */ packageJsonPath?: string; /** * Path to the folder where all built `.node` files put, same as `--output-dir` of build command * * @default './artifacts' */ outputDir?: string; /** * Path to the folder where the npm packages put * * @default 'npm' */ npmDir?: string; /** * Path to the build output dir, only needed when targets contain a WASI target */ buildOutputDir?: string; } //#endregion //#region src/api/artifacts.d.ts declare function collectArtifacts(userOptions: ArtifactsOptions): Promise<void>; //#endregion //#region src/def/build.d.ts declare abstract class BaseBuildCommand extends Command { static paths: string[][]; static usage: import("clipanion").Usage; target?: string; cwd?: string; manifestPath?: string; configPath?: string; packageJsonPath?: string; targetDir?: string; outputDir?: string; platform?: boolean; jsPackageName?: string; constEnum?: boolean; runtimeStringEnum?: boolean; jsBinding?: string; noJsBinding?: boolean; dts?: string; dtsHeader?: string; noDtsHeader?: boolean; dtsCache: boolean; esm?: boolean; strip?: boolean; release?: boolean; verbose?: boolean; bin?: string; package?: string; profile?: string; crossCompile?: boolean; useCross?: boolean; useNapiCross?: boolean; watch?: boolean; features?: string[]; allFeatures?: boolean; noDefaultFeatures?: boolean; getOptions(): { target: string | undefined; cwd: string | undefined; manifestPath: string | undefined; configPath: string | undefined; packageJsonPath: string | undefined; targetDir: string | undefined; outputDir: string | undefined; platform: boolean | undefined; jsPackageName: string | undefined; constEnum: boolean | undefined; runtimeStringEnum: boolean | undefined; jsBinding: string | undefined; noJsBinding: boolean | undefined; dts: string | undefined; dtsHeader: string | undefined; noDtsHeader: boolean | undefined; dtsCache: boolean; esm: boolean | undefined; strip: boolean | undefined; release: boolean | undefined; verbose: boolean | undefined; bin: string | undefined; package: string | undefined; profile: string | undefined; crossCompile: boolean | undefined; useCross: boolean | undefined; useNapiCross: boolean | undefined; watch: boolean | undefined; features: string[] | undefined; allFeatures: boolean | undefined; noDefaultFeatures: boolean | undefined; }; } /** * Build the NAPI-RS project */ interface BuildOptions$1 { /** * Build for the target triple, bypassed to `cargo build --target` */ target?: string; /** * The working directory of where napi command will be executed in, all other paths options are relative to this path */ cwd?: string; /** * Path to `Cargo.toml` */ manifestPath?: string; /** * Path to `napi` config json file */ configPath?: string; /** * Path to `package.json` */ packageJsonPath?: string; /** * Directory for all crate generated artifacts, see `cargo build --target-dir` */ targetDir?: string; /** * Path to where all the built files would be put. Default to the crate folder */ outputDir?: string; /** * Add platform triple to the generated nodejs binding file, eg: `[name].linux-x64-gnu.node` */ platform?: boolean; /** * Package name in generated js binding file. Only works with `--platform` flag */ jsPackageName?: string; /** * Whether generate const enum for typescript bindings */ constEnum?: boolean; /** * Emit `#[napi(string_enum)]` enums as runtime enums (`export declare enum`) under `--no-const-enum`. Default: type-only union. */ runtimeStringEnum?: boolean; /** * Path and filename of generated JS binding file. Only works with `--platform` flag. Relative to `--output-dir`. */ jsBinding?: string; /** * Whether to disable the generation JS binding file. Only works with `--platform` flag. */ noJsBinding?: boolean; /** * Path and filename of generated type def file. Relative to `--output-dir` */ dts?: string; /** * Custom file header for generated type def file. Only works when `typedef` feature enabled. */ dtsHeader?: string; /** * Whether to disable the default file header for generated type def file. Only works when `typedef` feature enabled. */ noDtsHeader?: boolean; /** * Whether to enable the dts cache, default to true * * @default true */ dtsCache?: boolean; /** * Whether to emit an ESM JS binding file instead of CJS format. Only works with `--platform` flag. */ esm?: boolean; /** * Whether strip the library to achieve the minimum file size */ strip?: boolean; /** * Build in release mode */ release?: boolean; /** * Verbosely log build command trace */ verbose?: boolean; /** * Build only the specified binary */ bin?: string; /** * Build the specified library or the one at cwd */ package?: string; /** * Build artifacts with the specified profile */ profile?: string; /** * [experimental] cross compile by replacing the cargo subcommand: Windows MSVC targets from a non-Windows host build with `cargo-xwin` (`windows-gnu` targets are rejected, `cargo-xwin` cannot handle them), non-Windows targets build with `cargo-zigbuild` (requires `zig` on PATH). The selected subcommand is auto-installed on first use. Cannot be combined with `--use-cross`, `--use-napi-cross` or `--watch` */ crossCompile?: boolean; /** * [experimental] not recommended, prefer `--cross-compile` or `--use-napi-cross`: build in a Docker or Podman container with [cross](https://github.com/cross-rs/cross), which must be installed manually and needs a running container engine. Cannot be combined with `--cross-compile`, `--use-napi-cross` or `--watch` */ useCross?: boolean; /** * [experimental] download a prebuilt gcc cross toolchain from `@napi-rs/cross-toolchain` (glibc 2.17) and set linker and C compiler environment variables. Linux glibc targets only (x64, arm64, armv7, ppc64le, s390x) on a Linux x64 or arm64 host, any other target or host errors. Cannot be combined with `--cross-compile` or `--use-cross` */ useNapiCross?: boolean; /** * watch the crate changes and build continuously with `cargo-watch` crates */ watch?: boolean; /** * Space-separated list of features to activate */ features?: string[]; /** * Activate all available features */ allFeatures?: boolean; /** * Do not activate the `default` feature */ noDefaultFeatures?: boolean; } //#endregion //#region src/utils/log.d.ts declare module 'obug' { interface Debugger { info: typeof console.error; warn: typeof console.error; error: typeof console.error; } } //#endregion //#region src/utils/target.d.ts type Platform = NodeJS.Platform | 'wasm' | 'wasi' | 'openharmony'; type NodeJSArch = 'arm' | 'arm64' | 'ia32' | 'loong64' | 'mips' | 'mipsel' | 'ppc' | 'ppc64' | 'riscv64' | 's390' | 's390x' | 'x32' | 'x64' | 'universal' | 'wasm32'; interface Target { triple: string; platformArchABI: string; platform: Platform; arch: NodeJSArch; abi: string | null; } /** * A triple is a specific format for specifying a target architecture. * Triples may be referred to as a target triple which is the architecture for the artifact produced, and the host triple which is the architecture that the compiler is running on. * The general format of the triple is `<arch><sub>-<vendor>-<sys>-<abi>` where: * - `arch` = The base CPU architecture, for example `x86_64`, `i686`, `arm`, `thumb`, `mips`, etc. * - `sub` = The CPU sub-architecture, for example `arm` has `v7`, `v7s`, `v5te`, etc. * - `vendor` = The vendor, for example `unknown`, `apple`, `pc`, `nvidia`, etc. * - `sys` = The system name, for example `linux`, `windows`, `darwin`, etc. none is typically used for bare-metal without an OS. * - `abi` = The ABI, for example `gnu`, `android`, `eabi`, etc. */ declare function parseTriple(rawTriple: string): Target; //#endregion //#region src/utils/config.d.ts interface UserNapiConfig { /** * Name of the binary to be generated, default to `index` */ binaryName?: string; /** * Name of the npm package, default to the name of root package.json name * * Always given `@scope/pkg` and arch suffix will be appended like `@scope/pkg-linux-gnu-x64` */ packageName?: string; /** * All targets the crate will be compiled for */ targets?: string[]; /** * The npm client project uses. */ npmClient?: string; /** * Whether generate const enum for typescript bindings */ constEnum?: boolean; /** * Emit `#[napi(string_enum)]` enums as runtime enums (`export declare enum`) under `--no-const-enum`. Default: type-only union. */ runtimeStringEnum?: boolean; /** * dts header prepend to the generated dts file */ dtsHeader?: string; /** * dts header file path to be prepended to the generated dts file * if both dtsHeader and dtsHeaderFile are provided, dtsHeaderFile will be used */ dtsHeaderFile?: string; /** * wasm compilation options */ wasm?: { /** * https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Memory * @default 4000 pages (250 MiB), or 1024 pages (64 MiB) for the deferred workerd loader */ initialMemory?: number; /** * @default 65536 pages (4GiB) */ maximumMemory?: number; /** * Whether the generated `<packageName>-wasm32-wasi` package is declared as * an `optionalDependency` of the root package. * * When native targets are configured the WASI package is a fallback for * hosts that cannot load a `.node` binary, so declaring it would make every * consumer download the `.wasm` binary they will never load. It is * therefore omitted by default and is expected to be installed on demand by * the environments that need it. * * When WASI is the only configured target it is the primary artifact and is * declared by default. * * Set this explicitly to override either default. * * @default true when every configured target is WASI, false otherwise */ optionalDependency?: boolean; /** * Browser wasm binding configuration */ browser?: { /** * Whether to use fs module in browser */ fs?: boolean; /** * Whether to initialize wasm asynchronously */ asyncInit?: boolean; /** * Whether to inject `buffer` to emnapi context */ buffer?: boolean; /** * Whether to emit custom events for errors in worker */ errorEvent?: boolean; }; }; /** * @deprecated binaryName instead */ name?: string; /** * @deprecated use packageName instead */ package?: { name?: string; }; /** * @deprecated use targets instead */ triples?: { /** * Whether enable default targets */ defaults: boolean; /** * Additional targets to be compiled for */ additional?: string[]; }; } interface CommonPackageJsonFields { name: string; version: string; description?: string; keywords?: string[]; author?: string; authors?: string[]; license?: string; cpu?: string[]; os?: string[]; libc?: string[]; files?: string[]; repository?: any; homepage?: any; engines?: Record<string, string>; publishConfig?: any; bugs?: any; napi?: UserNapiConfig; type?: 'module' | 'commonjs'; scripts?: Record<string, string>; main?: string; module?: string; types?: string; browser?: string; exports?: any; dependencies?: Record<string, string>; devDependencies?: Record<string, string>; optionalDependencies?: Record<string, string>; ava?: { timeout?: string; }; } type NapiConfig = Required<Pick<UserNapiConfig, 'binaryName' | 'packageName' | 'npmClient'>> & Pick<UserNapiConfig, 'wasm' | 'dtsHeader' | 'dtsHeaderFile' | 'constEnum' | 'runtimeStringEnum'> & { targets: Target[]; packageJson: CommonPackageJsonFields; }; declare function readNapiConfig(path: string, configPath?: string): Promise<NapiConfig>; //#endregion //#region src/api/build.d.ts type OutputKind = 'js' | 'dts' | 'node' | 'exe' | 'wasm'; type Output = { kind: OutputKind; path: string; }; type BuildOptions = BuildOptions$1 & { cargoOptions?: string[]; }; declare function buildProject(rawOptions: BuildOptions): Promise<{ task: Promise<Output[]>; abort: () => void; }>; interface WriteJsBindingOptions { platform?: boolean; noJsBinding?: boolean; idents: string[]; jsBinding?: string; esm?: boolean; binaryName: string; packageName: string; version: string; outputDir: string; /** * `platformArchABI`s of the declared WASI targets in fallback preference * order (threaded first). Defaults to the legacy `['wasm32-wasi']` chain * when omitted or empty. Generated loaders expose these exact identities * through `NAPI_RS_WASI_FLAVOR`. */ wasiFlavors?: string[]; } declare function writeJsBinding(options: WriteJsBindingOptions): Promise<Output | undefined>; interface GenerateTypeDefOptions { typeDefDir: string; noDtsHeader?: boolean; dtsHeader?: string; dtsHeaderFile?: string; configDtsHeader?: string; configDtsHeaderFile?: string; constEnum?: boolean; runtimeStringEnum?: boolean; cwd: string; } /** * Walk the napi-derive intermediate type-def directory, render every entry * into TypeScript via {@link processTypeDef}, and return the concatenated * `.d.ts` source plus the list of identifiers to re-export from * `index.js`. */ declare function generateTypeDef(options: GenerateTypeDefOptions): Promise<{ exports: string[]; dts: string; dtsWithTypeImports: string; }>; //#endregion //#region src/def/create-npm-dirs.d.ts declare abstract class BaseCreateNpmDirsCommand extends Command { static paths: string[][]; static usage: import("clipanion").Usage; cwd: string; configPath?: string; packageJsonPath: string; npmDir: string; dryRun: boolean; getOptions(): { cwd: string; configPath: string | undefined; packageJsonPath: string; npmDir: string; dryRun: boolean; }; } /** * Create npm package dirs for different platforms */ interface CreateNpmDirsOptions { /** * The working directory of where napi command will be executed in, all other paths options are relative to this path * * @default process.cwd() */ cwd?: string; /** * Path to `napi` config json file */ configPath?: string; /** * Path to `package.json` * * @default 'package.json' */ packageJsonPath?: string; /** * Path to the folder where the npm packages put * * @default 'npm' */ npmDir?: string; /** * Dry run without touching file system * * @default false */ dryRun?: boolean; } //#endregion //#region src/api/create-npm-dirs.d.ts declare function createNpmDirs(userOptions: CreateNpmDirsOptions): Promise<void>; //#endregion //#region src/def/new.d.ts declare abstract class BaseNewCommand extends Command { static paths: string[][]; static usage: import("clipanion").Usage; $$path: string | undefined; $$name?: string; minNodeApiVersion: number; packageManager: string; license: string; targets: string[]; enableDefaultTargets: boolean; enableAllTargets: boolean; enableTypeDef: boolean; enableGithubActions: boolean; testFramework: string; dryRun: boolean; getOptions(): { path: string | undefined; name: string | undefined; minNodeApiVersion: number; packageManager: string; license: string; targets: string[]; enableDefaultTargets: boolean; enableAllTargets: boolean; enableTypeDef: boolean; enableGithubActions: boolean; testFramework: string; dryRun: boolean; }; } /** * Create a new project with pre-configured boilerplate */ interface NewOptions { /** * The path where the NAPI-RS project will be created. */ path?: string; /** * The name of the project, default to the name of the directory if not provided */ name?: string; /** * The minimum Node-API version to support * * @default 4 */ minNodeApiVersion?: number; /** * The package manager to use. Only support yarn 4.x for now. * * @default 'yarn' */ packageManager?: string; /** * License for open-sourced project * * @default 'MIT' */ license?: string; /** * All targets the crate will be compiled for. * * @default [] */ targets?: string[]; /** * Whether enable default targets * * @default true */ enableDefaultTargets?: boolean; /** * Whether enable all targets * * @default false */ enableAllTargets?: boolean; /** * Whether enable the `type-def` feature for typescript definitions auto-generation * * @default true */ enableTypeDef?: boolean; /** * Whether generate preconfigured GitHub Actions workflow * * @default true */ enableGithubActions?: boolean; /** * The JavaScript test framework to use, only support `ava` for now * * @default 'ava' */ testFramework?: string; /** * Whether to run the command in dry-run mode * * @default false */ dryRun?: boolean; } //#endregion //#region src/api/new.d.ts declare function newProject(userOptions: NewOptions): Promise<void>; //#endregion //#region src/def/pre-publish.d.ts declare abstract class BasePrePublishCommand extends Command { static paths: string[][]; static usage: import("clipanion").Usage; cwd: string; configPath?: string; packageJsonPath: string; npmDir: string; tagStyle: string; ghRelease: boolean; ghReleaseName?: string; ghReleaseId?: string; skipOptionalPublish: boolean; dryRun: boolean; getOptions(): { cwd: string; configPath: string | undefined; packageJsonPath: string; npmDir: string; tagStyle: string; ghRelease: boolean; ghReleaseName: string | undefined; ghReleaseId: string | undefined; skipOptionalPublish: boolean; dryRun: boolean; }; } /** * Update package.json and copy addons into per platform packages */ interface PrePublishOptions { /** * The working directory of where napi command will be executed in, all other paths options are relative to this path * * @default process.cwd() */ cwd?: string; /** * Path to `napi` config json file */ configPath?: string; /** * Path to `package.json` * * @default 'package.json' */ packageJsonPath?: string; /** * Path to the folder where the npm packages put * * @default 'npm' */ npmDir?: string; /** * git tag style, `npm` or `lerna` * * @default 'lerna' */ tagStyle?: 'npm' | 'lerna'; /** * Whether create GitHub release * * @default true */ ghRelease?: boolean; /** * GitHub release name */ ghReleaseName?: string; /** * Existing GitHub release id */ ghReleaseId?: string; /** * Whether skip optionalDependencies packages publish * * @default false */ skipOptionalPublish?: boolean; /** * Dry run without touching file system * * @default false */ dryRun?: boolean; } //#endregion //#region src/api/pre-publish.d.ts declare function prePublish(userOptions: PrePublishOptions): Promise<void>; //#endregion //#region src/def/rename.d.ts declare abstract class BaseRenameCommand extends Command { static paths: string[][]; static usage: import("clipanion").Usage; cwd: string; configPath?: string; packageJsonPath: string; npmDir: string; $$name?: string; binaryName?: string; packageName?: string; manifestPath: string; repository?: string; description?: string; getOptions(): { cwd: string; configPath: string | undefined; packageJsonPath: string; npmDir: string; name: string | undefined; binaryName: string | undefined; packageName: string | undefined; manifestPath: string; repository: string | undefined; description: string | undefined; }; } /** * Rename the NAPI-RS project */ interface RenameOptions { /** * The working directory of where napi command will be executed in, all other paths options are relative to this path * * @default process.cwd() */ cwd?: string; /** * Path to `napi` config json file */ configPath?: string; /** * Path to `package.json` * * @default 'package.json' */ packageJsonPath?: string; /** * Path to the folder where the npm packages put * * @default 'npm' */ npmDir?: string; /** * The new name of the project */ name?: string; /** * The new binary name *.node files */ binaryName?: string; /** * The new package name of the project */ packageName?: string; /** * Path to `Cargo.toml` * * @default 'Cargo.toml' */ manifestPath?: string; /** * The new repository of the project */ repository?: string; /** * The new description of the project */ description?: string; } //#endregion //#region src/api/rename.d.ts declare function renameProject(userOptions: RenameOptions): Promise<void>; //#endregion //#region src/def/universalize.d.ts declare abstract class BaseUniversalizeCommand extends Command { static paths: string[][]; static usage: import("clipanion").Usage; cwd: string; configPath?: string; packageJsonPath: string; outputDir: string; getOptions(): { cwd: string; configPath: string | undefined; packageJsonPath: string; outputDir: string; }; } /** * Combile built binaries into one universal binary */ interface UniversalizeOptions { /** * The working directory of where napi command will be executed in, all other paths options are relative to this path * * @default process.cwd() */ cwd?: string; /** * Path to `napi` config json file */ configPath?: string; /** * Path to `package.json` * * @default 'package.json' */ packageJsonPath?: string; /** * Path to the folder where all built `.node` files put, same as `--output-dir` of build command * * @default './' */ outputDir?: string; } //#endregion //#region src/api/universalize.d.ts declare function universalizeBinaries(userOptions: UniversalizeOptions): Promise<void>; //#endregion //#region src/def/version.d.ts declare abstract class BaseVersionCommand extends Command { static paths: string[][]; static usage: import("clipanion").Usage; cwd: string; configPath?: string; packageJsonPath: string; npmDir: string; getOptions(): { cwd: string; configPath: string | undefined; packageJsonPath: string; npmDir: string; }; } /** * Update version in created npm packages */ interface VersionOptions { /** * The working directory of where napi command will be executed in, all other paths options are relative to this path * * @default process.cwd() */ cwd?: string; /** * Path to `napi` config json file */ configPath?: string; /** * Path to `package.json` * * @default 'package.json' */ packageJsonPath?: string; /** * Path to the folder where the npm packages put * * @default 'npm' */ npmDir?: string; } //#endregion //#region src/api/version.d.ts declare function version$1(userOptions: VersionOptions): Promise<void>; //#endregion //#region src/commands/artifacts.d.ts declare class ArtifactsCommand extends BaseArtifactsCommand { static usage: import("clipanion").Usage; static paths: string[][]; execute(): Promise<void>; } //#endregion //#region src/commands/build.d.ts declare class BuildCommand extends BaseBuildCommand { pipe: string | undefined; cargoOptions: string[]; execute(): Promise<void>; } //#endregion //#region src/commands/create-npm-dirs.d.ts declare class CreateNpmDirsCommand extends BaseCreateNpmDirsCommand { execute(): Promise<void>; } //#endregion //#region src/commands/new.d.ts declare class NewCommand extends BaseNewCommand { interactive: boolean; execute(): Promise<0 | 1>; private fetchOptions; private fetchName; private fetchLicense; private fetchNapiVersion; private fetchTargets; private fetchTypeDef; private fetchGithubActions; } //#endregion //#region src/commands/pre-publish.d.ts declare class PrePublishCommand extends BasePrePublishCommand { execute(): Promise<void>; } //#endregion //#region src/commands/rename.d.ts declare class RenameCommand extends BaseRenameCommand { execute(): Promise<void>; } //#endregion //#region src/commands/universalize.d.ts declare class UniversalizeCommand extends BaseUniversalizeCommand { execute(): Promise<void>; } //#endregion //#region src/commands/version.d.ts declare class VersionCommand extends BaseVersionCommand { execute(): Promise<void>; } //#endregion //#region src/index.d.ts declare const cli: Cli<import("clipanion").BaseContext>; /** * * @usage * * ```ts * const cli = new NapiCli() * * cli.build({ * cwd: '/path/to/your/project', * }) * ``` */ declare class NapiCli { artifacts: typeof collectArtifacts; new: typeof newProject; build: typeof buildProject; createNpmDirs: typeof createNpmDirs; prePublish: typeof prePublish; rename: typeof renameProject; universalize: typeof universalizeBinaries; version: typeof version$1; } declare function createBuildCommand(args: string[]): BuildCommand; declare function createArtifactsCommand(args: string[]): ArtifactsCommand; declare function createCreateNpmDirsCommand(args: string[]): CreateNpmDirsCommand; declare function createPrePublishCommand(args: string[]): PrePublishCommand; declare function createRenameCommand(args: string[]): RenameCommand; declare function createUniversalizeCommand(args: string[]): UniversalizeCommand; declare function createVersionCommand(args: string[]): VersionCommand; declare function createNewCommand(args: string[]): NewCommand; //#endregion export { type GenerateTypeDefOptions, NapiCli, type WriteJsBindingOptions, cli, createArtifactsCommand, createBuildCommand, createCreateNpmDirsCommand, createNewCommand, createPrePublishCommand, createRenameCommand, createUniversalizeCommand, createVersionCommand, generateTypeDef, parseTriple, readNapiConfig, writeJsBinding }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC5jdHMiLCJuYW1lcyI6WyJCdWlsZE9wdGlvbnMiLCJSYXdCdWlsZE9wdGlvbnMiLCJSYXdOZXdPcHRpb25zIiwidmVyc2lvbiIsInZlcnNpb24iXSwic291cmNlcyI6WyIuLi9zcmMvZGVmL2FydGlmYWN0cy5kLnRzIiwiLi4vc3JjL2FwaS9hcnRpZmFjdHMuZC50cyIsIi4uL3NyYy9kZWYvYnVpbGQuZC50cyIsIi4uL3NyYy91dGlscy9sb2cuZC50cyIsIi4uL3NyYy91dGlscy90YXJnZXQuZC50cyIsIi4uL3NyYy91dGlscy9jb25maWcuZC50cyIsIi4uL3NyYy9hcGkvYnVpbGQuZC50cyIsIi4uL3NyYy9kZWYvY3JlYXRlLW5wbS1kaXJzLmQudHMiLCIuLi9zcmMvYXBpL2NyZWF0ZS1ucG0tZGlycy5kLnRzIiwiLi4vc3JjL2RlZi9uZXcuZC50cyIsIi4uL3NyYy9hcGkvbmV3LmQudHMiLCIuLi9zcmMvZGVmL3ByZS1wdWJsaXNoLmQudHMiLCIuLi9zcmMvYXBpL3ByZS1wdWJsaXNoLmQudHMiLCIuLi9zcmMvZGVmL3JlbmFtZS5kLnRzIiwiLi4vc3JjL2FwaS9yZW5hbWUuZC50cyIsIi4uL3NyYy9kZWYvdW5pdmVyc2FsaXplLmQudHMiLCIuLi9zcmMvYXBpL3VuaXZlcnNhbGl6ZS5kLnRzIiwiLi4vc3JjL2RlZi92ZXJzaW9uLmQudHMiLCIuLi9zcmMvYXBpL3ZlcnNpb24uZC50cyIsIi4uL3NyYy9jb21tYW5kcy9hcnRpZmFjdHMuZC50cyIsIi4uL3NyYy9jb21tYW5kcy9idWlsZC5kLnRzIiwiLi4vc3JjL2NvbW1hbmRzL2NyZWF0ZS1ucG0tZGlycy5kLnRzIiwiLi4vc3JjL2NvbW1hbmRzL25ldy5kLnRzIiwiLi4vc3JjL2NvbW1hbmRzL3ByZS1wdWJsaXNoLmQudHMiLCIuLi9zcmMvY29tbWFuZHMvcmVuYW1lLmQudHMiLCIuLi9zcmMvY29tbWFuZHMvdW5pdmVyc2FsaXplLmQudHMiLCIuLi9zcmMvY29tbWFuZHMvdmVyc2lvbi5kLnRzIiwiLi4vc3JjL2luZGV4LmQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tbWFuZCB9IGZyb20gJ2NsaXBhbmlvbic7XG5leHBvcnQgZGVjbGFyZSBhYnN0cmFjdCBjbGFzcyBCYXNlQXJ0aWZhY3RzQ29tbWFuZCBleHRlbmRzIENvbW1hbmQge1xuICAgIHN0YXRpYyBwYXRoczogc3RyaW5nW11bXTtcbiAgICBzdGF0aWMgdXNhZ2U6IGltcG9ydChcImNsaXBhbmlvblwiKS5Vc2FnZTtcbiAgICBjd2Q6IHN0cmluZztcbiAgICBjb25maWdQYXRoPzogc3RyaW5nO1xuICAgIHBhY2thZ2VKc29uUGF0aDogc3RyaW5nO1xuICAgIG91dHB1dERpcjogc3RyaW5nO1xuICAgIG5wbURpcjogc3RyaW5nO1xuICAgIGJ1aWxkT3V0cHV0RGlyPzogc3RyaW5nO1xuICAgIGdldE9wdGlvbnMoKToge1xuICAgICAgICBjd2Q6IHN0cmluZztcbiAgICAgICAgY29uZmlnUGF0aDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICBwYWNrYWdlSnNvblBhdGg6IHN0cmluZztcbiAgICAgICAgb3V0cHV0RGlyOiBzdHJpbmc7XG4gICAgICAgIG5wbURpcjogc3RyaW5nO1xuICAgICAgICBidWlsZE91dHB1dERpcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgIH07XG59XG4vKipcbiAqIENvcHkgYXJ0aWZhY3RzIGZyb20gR2l0aHViIEFjdGlvbnMgaW50byBucG0gcGFja2FnZXMgYW5kIHJlYWR5IHRvIHB1Ymxpc2hcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBcnRpZmFjdHNPcHRpb25zIHtcbiAgICAvKipcbiAgICAgKiBUaGUgd29ya2luZyBkaXJlY3Rvcnkgb2Ygd2hlcmUgbmFwaSBjb21tYW5kIHdpbGwgYmUgZXhlY3V0ZWQgaW4sIGFsbCBvdGhlciBwYXRocyBvcHRpb25zIGFyZSByZWxhdGl2ZSB0byB0aGlzIHBhdGhcbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IHByb2Nlc3MuY3dkKClcbiAgICAgKi9cbiAgICBjd2Q/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byBgbmFwaWAgY29uZmlnIGpzb24gZmlsZVxuICAgICAqL1xuICAgIGNvbmZpZ1BhdGg/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byBgcGFja2FnZS5qc29uYFxuICAgICAqXG4gICAgICogQGRlZmF1bHQgJ3BhY2thZ2UuanNvbidcbiAgICAgKi9cbiAgICBwYWNrYWdlSnNvblBhdGg/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byB0aGUgZm9sZGVyIHdoZXJlIGFsbCBidWlsdCBgLm5vZGVgIGZpbGVzIHB1dCwgc2FtZSBhcyBgLS1vdXRwdXQtZGlyYCBvZiBidWlsZCBjb21tYW5kXG4gICAgICpcbiAgICAgKiBAZGVmYXVsdCAnLi9hcnRpZmFjdHMnXG4gICAgICovXG4gICAgb3V0cHV0RGlyPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFBhdGggdG8gdGhlIGZvbGRlciB3aGVyZSB0aGUgbnBtIHBhY2thZ2VzIHB1dFxuICAgICAqXG4gICAgICogQGRlZmF1bHQgJ25wbSdcbiAgICAgKi9cbiAgICBucG1EaXI/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byB0aGUgYnVpbGQgb3V0cHV0IGRpciwgb25seSBuZWVkZWQgd2hlbiB0YXJnZXRzIGNvbnRhaW4gYSBXQVNJIHRhcmdldFxuICAgICAqL1xuICAgIGJ1aWxkT3V0cHV0RGlyPzogc3RyaW5nO1xufVxuZXhwb3J0IGRlY2xhcmUgZnVuY3Rpb24gYXBwbHlEZWZhdWx0QXJ0aWZhY3RzT3B0aW9ucyhvcHRpb25zOiBBcnRpZmFjdHNPcHRpb25zKToge1xuICAgIGN3ZDogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFBhdGggdG8gYG5hcGlgIGNvbmZpZyBqc29uIGZpbGVcbiAgICAgKi9cbiAgICBjb25maWdQYXRoPzogc3RyaW5nO1xuICAgIHBhY2thZ2VKc29uUGF0aDogc3RyaW5nO1xuICAgIG91dHB1dERpcjogc3RyaW5nO1xuICAgIG5wbURpcjogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFBhdGggdG8gdGhlIGJ1aWxkIG91dHB1dCBkaXIsIG9ubHkgbmVlZGVkIHdoZW4gdGFyZ2V0cyBjb250YWluIGEgV0FTSSB0YXJnZXRcbiAgICAgKi9cbiAgICBidWlsZE91dHB1dERpcj86IHN0cmluZztcbn07XG4iLCJpbXBvcnQgeyB0eXBlIEFydGlmYWN0c09wdGlvbnMgfSBmcm9tICcuLi9kZWYvYXJ0aWZhY3RzLmpzJztcbmV4cG9ydCBkZWNsYXJlIGZ1bmN0aW9uIGNvbGxlY3RBcnRpZmFjdHModXNlck9wdGlvbnM6IEFydGlmYWN0c09wdGlvbnMpOiBQcm9taXNlPHZvaWQ+O1xuIiwiaW1wb3J0IHsgQ29tbWFuZCB9IGZyb20gJ2NsaXBhbmlvbic7XG5leHBvcnQgZGVjbGFyZSBhYnN0cmFjdCBjbGFzcyBCYXNlQnVpbGRDb21tYW5kIGV4dGVuZHMgQ29tbWFuZCB7XG4gICAgc3RhdGljIHBhdGhzOiBzdHJpbmdbXVtdO1xuICAgIHN0YXRpYyB1c2FnZTogaW1wb3J0KFwiY2xpcGFuaW9uXCIpLlVzYWdlO1xuICAgIHRhcmdldD86IHN0cmluZztcbiAgICBjd2Q/OiBzdHJpbmc7XG4gICAgbWFuaWZlc3RQYXRoPzogc3RyaW5nO1xuICAgIGNvbmZpZ1BhdGg/OiBzdHJpbmc7XG4gICAgcGFja2FnZUpzb25QYXRoPzogc3RyaW5nO1xuICAgIHRhcmdldERpcj86IHN0cmluZztcbiAgICBvdXRwdXREaXI/OiBzdHJpbmc7XG4gICAgcGxhdGZvcm0/OiBib29sZWFuO1xuICAgIGpzUGFja2FnZU5hbWU/OiBzdHJpbmc7XG4gICAgY29uc3RFbnVtPzogYm9vbGVhbjtcbiAgICBydW50aW1lU3RyaW5nRW51bT86IGJvb2xlYW47XG4gICAganNCaW5kaW5nPzogc3RyaW5nO1xuICAgIG5vSnNCaW5kaW5nPzogYm9vbGVhbjtcbiAgICBkdHM/OiBzdHJpbmc7XG4gICAgZHRzSGVhZGVyPzogc3RyaW5nO1xuICAgIG5vRHRzSGVhZGVyPzogYm9vbGVhbjtcbiAgICBkdHNDYWNoZTogYm9vbGVhbjtcbiAgICBlc20/OiBib29sZWFuO1xuICAgIHN0cmlwPzogYm9vbGVhbjtcbiAgICByZWxlYXNlPzogYm9vbGVhbjtcbiAgICB2ZXJib3NlPzogYm9vbGVhbjtcbiAgICBiaW4/OiBzdHJpbmc7XG4gICAgcGFja2FnZT86IHN0cmluZztcbiAgICBwcm9maWxlPzogc3RyaW5nO1xuICAgIGNyb3NzQ29tcGlsZT86IGJvb2xlYW47XG4gICAgdXNlQ3Jvc3M/OiBib29sZWFuO1xuICAgIHVzZU5hcGlDcm9zcz86IGJvb2xlYW47XG4gICAgd2F0Y2g/OiBib29sZWFuO1xuICAgIGZlYXR1cmVzPzogc3RyaW5nW107XG4gICAgYWxsRmVhdHVyZXM/OiBib29sZWFuO1xuICAgIG5vRGVmYXVsdEZlYXR1cmVzPzogYm9vbGVhbjtcbiAgICBnZXRPcHRpb25zKCk6IHtcbiAgICAgICAgdGFyZ2V0OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgICAgIGN3ZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICBtYW5pZmVzdFBhdGg6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgY29uZmlnUGF0aDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICBwYWNrYWdlSnNvblBhdGg6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgdGFyZ2V0RGlyOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgICAgIG91dHB1dERpcjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICBwbGF0Zm9ybTogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgICAgICAganNQYWNrYWdlTmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICBjb25zdEVudW06IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIHJ1bnRpbWVTdHJpbmdFbnVtOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuICAgICAgICBqc0JpbmRpbmc6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgbm9Kc0JpbmRpbmc6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIGR0czogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICBkdHNIZWFkZXI6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgbm9EdHNIZWFkZXI6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIGR0c0NhY2hlOiBib29sZWFuO1xuICAgICAgICBlc206IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIHN0cmlwOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuICAgICAgICByZWxlYXNlOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuICAgICAgICB2ZXJib3NlOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuICAgICAgICBiaW46IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgcGFja2FnZTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICAgICAgICBwcm9maWxlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgICAgIGNyb3NzQ29tcGlsZTogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgICAgICAgdXNlQ3Jvc3M6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIHVzZU5hcGlDcm9zczogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgICAgICAgd2F0Y2g6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIGZlYXR1cmVzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcbiAgICAgICAgYWxsRmVhdHVyZXM6IGJvb2xlYW4gfCB1bmRlZmluZWQ7XG4gICAgICAgIG5vRGVmYXVsdEZlYXR1cmVzOiBib29sZWFuIHwgdW5kZWZpbmVkO1xuICAgIH07XG59XG4vKipcbiAqIEJ1aWxkIHRoZSBOQVBJLVJTIHByb2plY3RcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCdWlsZE9wdGlvbnMge1xuICAgIC8qKlxuICAgICAqIEJ1aWxkIGZvciB0aGUgdGFyZ2V0IHRyaXBsZSwgYnlwYXNzZWQgdG8gYGNhcmdvIGJ1aWxkIC0tdGFyZ2V0YFxuICAgICAqL1xuICAgIHRhcmdldD86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBUaGUgd29ya2luZyBkaXJlY3Rvcnkgb2Ygd2hlcmUgbmFwaSBjb21tYW5kIHdpbGwgYmUgZXhlY3V0ZWQgaW4sIGFsbCBvdGhlciBwYXRocyBvcHRpb25zIGFyZSByZWxhdGl2ZSB0byB0aGlzIHBhdGhcbiAgICAgKi9cbiAgICBjd2Q/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byBgQ2FyZ28udG9tbGBcbiAgICAgKi9cbiAgICBtYW5pZmVzdFBhdGg/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byBgbmFwaWAgY29uZmlnIGpzb24gZmlsZVxuICAgICAqL1xuICAgIGNvbmZpZ1BhdGg/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byBgcGFja2FnZS5qc29uYFxuICAgICAqL1xuICAgIHBhY2thZ2VKc29uUGF0aD86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBEaXJlY3RvcnkgZm9yIGFsbCBjcmF0ZSBnZW5lcmF0ZWQgYXJ0aWZhY3RzLCBzZWUgYGNhcmdvIGJ1aWxkIC0tdGFyZ2V0LWRpcmBcbiAgICAgKi9cbiAgICB0YXJnZXREaXI/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogUGF0aCB0byB3aGVyZSBhbGwgdGhlIGJ1aWx0IGZpbGVzIHdvdWxkIGJlIHB1dC4gRGVmYXVsdCB0byB0aGUgY3JhdGUgZm9sZGVyXG4gICAgICovXG4gICAgb3V0cHV0RGlyPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIEFkZCBwbGF0Zm9ybSB0cmlwbGUgdG8gdGhlIGdlbmVyYXRlZCBub2RlanMgYmluZGluZyBmaWxlLCBlZzogYFtuYW1lXS5saW51eC14NjQtZ251Lm5vZGVgXG4gICAgICovXG4gICAgcGxhdGZvcm0/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIFBhY2thZ2UgbmFtZSBpbiBnZW5lcmF0ZWQganMgYmluZGluZyBmaWxlLiBPbmx5IHdvcmtzIHdpdGggYC0tcGxhdGZvcm1gIGZsYWdcbiAgICAgKi9cbiAgICBqc1BhY2thZ2VOYW1lPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgZ2VuZXJhdGUgY29uc3QgZW51bSBmb3IgdHlwZXNjcmlwdCBiaW5kaW5nc1xuICAgICAqL1xuICAgIGNvbnN0RW51bT86IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogRW1pdCBgI1tuYXBpKHN0cmluZ19lbnVtKV1gIGVudW1zIGFzIHJ1bnRpbWUgZW51bXMgKGBleHBvcnQgZGVjbGFyZSBlbnVtYCkgdW5kZXIgYC0tbm8tY29uc3QtZW51bWAuIERlZmF1bHQ6IHR5cGUtb25seSB1bmlvbi5cbiAgICAgKi9cbiAgICBydW50aW1lU3RyaW5nRW51bT86IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogUGF0aCBhbmQgZmlsZW5hbWUgb2YgZ2VuZXJhdGVkIEpTIGJpbmRpbmcgZmlsZS4gT25seSB3b3JrcyB3aXRoIGAtLXBsYXRmb3JtYCBmbGFnLiBSZWxhdGl2ZSB0byBgLS1vdXRwdXQtZGlyYC5cbiAgICAgKi9cbiAgICBqc0JpbmRpbmc/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogV2hldGhlciB0byBkaXNhYmxlIHRoZSBnZW5lcmF0aW9uIEpTIGJpbmRpbmcgZmlsZS4gT25seSB3b3JrcyB3aXRoIGAtLXBsYXRmb3JtYCBmbGFnLlxuICAgICAqL1xuICAgIG5vSnNCaW5kaW5nPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBQYXRoIGFuZCBmaWxlbmFtZSBvZiBnZW5lcmF0ZWQgdHlwZSBkZWYgZmlsZS4gUmVsYXRpdmUgdG8gYC0tb3V0cHV0LWRpcmBcbiAgICAgKi9cbiAgICBkdHM/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogQ3VzdG9tIGZpbGUgaGVhZGVyIGZvciBnZW5lcmF0ZWQgdHlwZSBkZWYgZmlsZS4gT25seSB3b3JrcyB3aGVuIGB0eXBlZGVmYCBmZWF0dXJlIGVuYWJsZWQuXG4gICAgICovXG4gICAgZHRzSGVhZGVyPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdG8gZGlzYWJsZSB0aGUgZGVmYXVsdCBmaWxlIGhlYWRlciBmb3IgZ2VuZXJhdGVkIHR5cGUgZGVmIGZpbGUuIE9ubHkgd29ya3Mgd2hlbiBgdHlwZWRlZmAgZmVhdHVyZSBlbmFibGVkLlxuICAgICAqL1xuICAgIG5vRHRzSGVhZGVyPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRvIGVuYWJsZSB0aGUgZHRzIGNhY2hlLCBkZWZhdWx0IHRvIHRydWVcbiAgICAgKlxuICAgICAqIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICBkdHNDYWNoZT86IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogV2hldGhlciB0byBlbWl0IGFuIEVTTSBKUyBiaW5kaW5nIGZpbGUgaW5zdGVhZCBvZiBDSlMgZm9ybWF0LiBPbmx5IHdvcmtzIHdpdGggYC0tcGxhdGZvcm1gIGZsYWcuXG4gICAgICovXG4gICAgZXNtPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHN0cmlwIHRoZSBsaWJyYXJ5IHRvIGFjaGlldmUgdGhlIG1pbmltdW0gZmlsZSBzaXplXG4gICAgICovXG4gICAgc3RyaXA/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIEJ1aWxkIGluIHJlbGVhc2UgbW9kZVxuICAgICAqL1xuICAgIHJlbGVhc2U/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIFZlcmJvc2VseSBsb2cgYnVpbGQgY29tbWFuZCB0cmFjZVxuICAgICAqL1xuICAgIHZlcmJvc2U/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIEJ1aWxkIG9ubHkgdGhlIHNwZWNpZmllZCBiaW5hcnlcbiAgICAgKi9cbiAgICBiaW4/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogQnVpbGQgdGhlIHNwZWNpZmllZCBsaWJyYXJ5IG9yIHRoZSBvbmUgYXQgY3dkXG4gICAgICovXG4gICAgcGFja2FnZT86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBCdWlsZCBhcnRpZmFjdHMgd2l0aCB0aGUgc3BlY2lmaWVkIHByb2ZpbGVcbiAgICAgKi9cbiAgICBwcm9maWxlPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFtleHBlcmltZW50YWxdIGNyb3NzIGNvbXBpbGUgYnkgcmVwbGFjaW5nIHRoZSBjYXJnbyBzdWJjb21tYW5kOiBXaW5kb3dzIE1TVkMgdGFyZ2V0cyBmcm9tIGEgbm9uLVdpbmRvd3MgaG9zdCBidWlsZCB3aXRoIGBjYXJnby14d2luYCAoYHdpbmRvd3MtZ251YCB0YXJnZXRzIGFyZSByZWplY3RlZCwgYGNhcmdvLXh3aW5gIGNhbm5vdCBoYW5kbGUgdGhlbSksIG5vbi1XaW5kb3dzIHRhcmdldHMgYnVpbGQgd2l0aCBgY2FyZ28temlnYnVpbGRgIChyZXF1aXJlcyBgemlnYCBvbiBQQVRIKS4gVGhlIHNlbGVjdGVkIHN1YmNvbW1hbmQgaXMgYXV0by1pbnN0YWxsZWQgb24gZmlyc3QgdXNlLiBDYW5ub3QgYmUgY29tYmluZWQgd2l0aCBgLS11c2UtY3Jvc3NgLCBgLS11c2UtbmFwaS1jcm9zc2Agb3IgYC0td2F0Y2hgXG4gICAgICovXG4gICAgY3Jvc3NDb21waWxlPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBbZXhwZXJpbWVudGFsXSBub3QgcmVjb21tZW5kZWQsIHByZWZlciBgLS1jcm9zcy1jb21waWxlYCBvciBgLS11c2UtbmFwaS1jcm9zc2A6IGJ1aWxkIGluIGEgRG9ja2VyIG9yIFBvZG1hbiBjb250YWluZXIgd2l0aCBbY3Jvc3NdKGh0dHBzOi8vZ2l0aHViLmNvbS9jcm9zcy1ycy9jcm9zcyksIHdoaWNoIG11c3QgYmUgaW5zdGFsbGVkIG1hbnVhbGx5IGFuZCBuZWVkcyBhIHJ1bm5pbmcgY29udGFpbmVyIGVuZ2luZS4gQ2Fubm90IGJlIGNvbWJpbmVkIHdpdGggYC0tY3Jvc3MtY29tcGlsZWAsIGAtLXVzZS1uYXBpLWNyb3NzYCBvciBgLS13YXRjaGBcbiAgICAgKi9cbiAgICB1c2VDcm9zcz86IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogW2V4cGVyaW1lbnRhbF0gZG93bmxvYWQgYSBwcmVidWlsdCBnY2MgY3Jvc3MgdG9vbGNoYWluIGZyb20gYEBuYXBpLXJzL2Nyb3NzLXRvb2xjaGFpbmAgKGdsaWJjIDIuMTcpIGFuZCBzZXQgbGlua2VyIGFuZCBDIGNvbXBpbGVyIGVudmlyb25tZW50IHZhcmlhYmxlcy4gTGludXggZ2xpYmMgdGFyZ2V0cyBvbmx5ICh4NjQsIGFybTY0LCBhcm12NywgcHBjNjRsZSwgczM5MHgpIG9uIGEgTGludXggeDY0IG9yIGFybTY0IGhvc3QsIGFueSBvdGhlciB0YXJnZXQgb3IgaG9zdCBlcnJvcnMuIENhbm5vdCBiZSBjb21iaW5lZCB3aXRoIGAtLWNyb3NzLWNvbXBpbGVgIG9yIGAtLXVzZS1jcm9zc2BcbiAgICAgKi9cbiAgICB1c2VOYXBpQ3Jvc3M/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIHdhdGNoIHRoZSBjcmF0ZSBjaGFuZ2VzIGFuZCBidWlsZCBjb250aW51b3VzbHkgd2l0aCBgY2FyZ28td2F0Y2hgIGNyYXRlc1xuICAgICAqL1xuICAgIHdhdGNoPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBTcGFjZS1zZXBhcmF0ZWQgbGlzdCBvZiBmZWF0dXJlcyB0byBhY3RpdmF0ZVxuICAgICAqL1xuICAgIGZlYXR1cmVzPzogc3RyaW5nW107XG4gICAgLyoqXG4gICAgICogQWN0aXZhdGUgYWxsIGF2YWlsYWJsZSBmZWF0dXJlc1xuICAgICAqL1xuICAgIGFsbEZlYXR1cmVzPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBEbyBub3QgYWN0aXZhdGUgdGhlIGBkZWZhdWx0YCBmZWF0dXJlXG4gICAgICovXG4gICAgbm9EZWZhdWx0RmVhdHVyZXM/OiBib29sZWFuO1xufVxuZXhwb3J0IGRlY2xhcmUgZnVuY3Rpb24gYXBwbHlEZWZhdWx0QnVpbGRPcHRpb25zKG9wdGlvbnM6IEJ1aWxkT3B0aW9ucyk6IHtcbiAgICAvKipcbiAgICAgKiBCdWlsZCBmb3IgdGhlIHRhcmdldCB0cmlwbGUsIGJ5cGFzc2VkIHRvIGBjYXJnbyBidWlsZCAtLXRhcmdldGBcbiAgICAgKi9cbiAgICB0YXJnZXQ/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogVGhlIHdvcmtpbmcgZGlyZWN0b3J5IG9mIHdoZXJlIG5hcGkgY29tbWFuZCB3aWxsIGJlIGV4ZWN1dGVkIGluLCBhbGwgb3RoZXIgcGF0aHMgb3B0aW9ucyBhcmUgcmVsYXRpdmUgdG8gdGhpcyBwYXRoXG4gICAgICovXG4gICAgY3dkPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFBhdGggdG8gYENhcmdvLnRvbWxgXG4gICAgICovXG4gICAgbWFuaWZlc3RQYXRoPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFBhdGggdG8gYG5hcGlgIGNvbmZpZyBqc29uIGZpbGVcbiAgICAgKi9cbiAgICBjb25maWdQYXRoPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFBhdGggdG8gYHBhY2thZ2UuanNvbmBcbiAgICAgKi9cbiAgICBwYWNrYWdlSnNvblBhdGg/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogRGlyZWN0b3J5IGZvciBhbGwgY3JhdGUgZ2VuZXJhdGVkIGFydGlmYWN0cywgc2VlIGBjYXJnbyBidWlsZCAtLXRhcmdldC1kaXJgXG4gICAgICovXG4gICAgdGFyZ2V0RGlyPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFBhdGggdG8gd2hlcmUgYWxsIHRoZSBidWlsdCBmaWxlcyB3b3VsZCBiZSBwdXQuIERlZmF1bHQgdG8gdGhlIGNyYXRlIGZvbGRlclxuICAgICAqL1xuICAgIG91dHB1dERpcj86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBBZGQgcGxhdGZvcm0gdHJpcGxlIHRvIHRoZSBnZW5lcmF0ZWQgbm9kZWpzIGJpbmRpbmcgZmlsZSwgZWc6IGBbbmFtZV0ubGludXgteDY0LWdudS5ub2RlYFxuICAgICAqL1xuICAgIHBsYXRmb3JtPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBQYWNrYWdlIG5hbWUgaW4gZ2VuZXJhdGVkIGpzIGJpbmRpbmcgZmlsZS4gT25seSB3b3JrcyB3aXRoIGAtLXBsYXRmb3JtYCBmbGFnXG4gICAgICovXG4gICAganNQYWNrYWdlTmFtZT86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIGdlbmVyYXRlIGNvbnN0IGVudW0gZm9yIHR5cGVzY3JpcHQgYmluZGluZ3NcbiAgICAgKi9cbiAgICBjb25zdEVudW0/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIEVtaXQgYCNbbmFwaShzdHJpbmdfZW51bSldYCBlbnVtcyBhcyBydW50aW1lIGVudW1zIChgZXhwb3J0IGRlY2xhcmUgZW51bWApIHVuZGVyIGAtLW5vLWNvbnN0LWVudW1gLiBEZWZhdWx0OiB0eXBlLW9ubHkgdW5pb24uXG4gICAgICovXG4gICAgcnVudGltZVN0cmluZ0VudW0/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIFBhdGggYW5kIGZpbGVuYW1lIG9mIGdlbmVyYXRlZCBKUyBiaW5kaW5nIGZpbGUuIE9ubHkgd29ya3Mgd2l0aCBgLS1wbGF0Zm9ybWAgZmxhZy4gUmVsYXRpdmUgdG8gYC0tb3V0cHV0LWRpcmAuXG4gICAgICovXG4gICAganNCaW5kaW5nPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdG8gZGlzYWJsZSB0aGUgZ2VuZXJhdGlvbiBKUyBiaW5kaW5nIGZpbGUuIE9ubHkgd29ya3Mgd2l0aCBgLS1wbGF0Zm9ybWAgZmxhZy5cbiAgICAgKi9cbiAgICBub0pzQmluZGluZz86IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogUGF0aCBhbmQgZmlsZW5hbWUgb2YgZ2VuZXJhdGVkIHR5cGUgZGVmIGZpbGUuIFJlbGF0aXZlIHRvIGAtLW91dHB1dC1kaXJgXG4gICAgICovXG4gICAgZHRzPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIEN1c3RvbSBmaWxlIGhlYWRlciBmb3IgZ2VuZXJhdGVkIHR5cGUgZGVmIGZpbGUuIE9ubHkgd29ya3Mgd2hlbiBgdHlwZWRlZmAgZmVhdHVyZSBlbmFibGVkLlxuICAgICAqL1xuICAgIGR0c0hlYWRlcj86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRvIGRpc2FibGUgdGhlIGRlZmF1bHQgZmlsZSBoZWFkZXIgZm9yIGdlbmVyYXRlZCB0eXBlIGRlZiBmaWxlLiBPbmx5IHdvcmtzIHdoZW4gYHR5cGVkZWZgIGZlYXR1cmUgZW5hYmxlZC5cbiAgICAgKi9cbiAgICBub0R0c0hlYWRlcj86IGJvb2xlYW47XG4gICAgZHRzQ2FjaGU6IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogV2hldGhlciB0byBlbWl0IGFuIEVTTSBKUyBiaW5kaW5nIGZpbGUgaW5zdGVhZCBvZiBDSlMgZm9ybWF0LiBPbmx5IHdvcmtzIHdpdGggYC0tcGxhdGZvcm1gIGZsYWcuXG4gICAgICovXG4gICAgZXNtPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHN0cmlwIHRoZSBsaWJyYXJ5IHRvIGFjaGlldmUgdGhlIG1pbmltdW0gZmlsZSBzaXplXG4gICAgICovXG4gICAgc3RyaXA/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIEJ1aWxkIGluIHJlbGVhc2UgbW9kZVxuICAgICAqL1xuICAgIHJlbGVhc2U/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIFZlcmJvc2VseSBsb2cgYnVpbGQgY29tbWFuZCB0cmFjZVxuICAgICAqL1xuICAgIHZlcmJvc2U/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIEJ1aWxkIG9ubHkgdGhlIHNwZWNpZmllZCBiaW5hcnlcbiAgICAgKi9cbiAgICBiaW4/OiBzdHJpbmc7XG4gICAgLyoqXG4gICAgICogQnVpbGQgdGhlIHNwZWNpZmllZCBsaWJyYXJ5IG9yIHRoZSBvbmUgYXQgY3dkXG4gICAgICovXG4gICAgcGFja2FnZT86IHN0cmluZztcbiAgICAvKipcbiAgICAgKiBCdWlsZCBhcnRpZmFjdHMgd2l0aCB0aGUgc3BlY2lmaWVkIHByb2ZpbGVcbiAgICAgKi9cbiAgICBwcm9maWxlPzogc3RyaW5nO1xuICAgIC8qKlxuICAgICAqIFtleHBlcmltZW50YWxdIGNyb3NzIGNvbXBpbGUgYnkgcmVwbGFjaW5nIHRoZSBjYXJnbyBzdWJjb21tYW5kOiBXaW5kb3dzIE1TVkMgdGFyZ2V0cyBmcm9tIGEgbm9uLVdpbmRvd3MgaG9zdCBidWlsZCB3aXRoIGBjYXJnby14d2luYCAoYHdpbmRvd3MtZ251YCB0YXJnZXRzIGFyZSByZWplY3RlZCwgYGNhcmdvLXh3aW5gIGNhbm5vdCBoYW5kbGUgdGhlbSksIG5vbi1XaW5kb3dzIHRhcmdldHMgYnVpbGQgd2l0aCBgY2FyZ28temlnYnVpbGRgIChyZXF1aXJlcyBgemlnYCBvbiBQQVRIKS4gVGhlIHNlbGVjdGVkIHN1YmNvbW1hbmQgaXMgYXV0by1pbnN0YWxsZWQgb24gZmlyc3QgdXNlLiBDYW5ub3QgYmUgY29tYmluZWQgd2l0aCBgLS11c2UtY3Jvc3NgLCBgLS11c2UtbmFwaS1jcm9zc2Agb3IgYC0td2F0Y2hgXG4gICAgICovXG4gICAgY3Jvc3NDb21waWxlPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBbZXhwZXJpbWVudGFsXSBub3QgcmVjb21tZW5kZWQsIHByZWZlciBgLS1jcm9zcy1jb21waWxlYCBvciBgLS11c2UtbmFwaS1jcm9zc2A6IGJ1aWxkIGluIGEgRG9ja2VyIG9yIFBvZG1hbiBjb250YWluZXIgd2l0aCBbY3Jvc3NdKGh0dHBzOi8vZ2l0aHViLmNvbS9jcm9zcy1ycy9jcm9zcyksIHdoaWNoIG11c3QgYmUgaW5zdGFsbGVkIG1hbnVhbGx5IGFuZCBuZWVkcyBhIHJ1bm5pbmcgY29udGFpbmVyIGVuZ2luZS4gQ2Fubm90IGJlIGNvbWJpbmVkIHdpdGggYC0tY3Jvc3MtY29tcGlsZWAsIGAtLXVzZS1uYXBpLWNyb3NzYCBvciBgLS13YXRjaGBcbiAgICAgKi9cbiAgICB1c2VDcm9zcz86IGJvb2xlYW47XG4gICAgLyoqXG4gICAgICogW2V4cGVyaW1lbnRhbF0gZG93bmxvYWQgYSBwcmVidWlsdCBnY2MgY3Jvc3MgdG9vbGNoYWluIGZyb20gYEBuYXBpLXJzL2Nyb3NzLXRvb2xjaGFpbmAgKGdsaWJjIDIuMTcpIGFuZCBzZXQgbGlua2VyIGFuZCBDIGNvbXBpbGVyIGVudmlyb25tZW50IHZhcmlhYmxlcy4gTGludXggZ2xpYmMgdGFyZ2V0cyBvbmx5ICh4NjQsIGFybTY0LCBhcm12NywgcHBjNjRsZSwgczM5MHgpIG9uIGEgTGludXggeDY0IG9yIGFybTY0IGhvc3QsIGFueSBvdGhlciB0YXJnZXQgb3IgaG9zdCBlcnJvcnMuIENhbm5vdCBiZSBjb21iaW5lZCB3aXRoIGAtLWNyb3NzLWNvbXBpbGVgIG9yIGAtLXVzZS1jcm9zc2BcbiAgICAgKi9cbiAgICB1c2VOYXBpQ3Jvc3M/OiBib29sZWFuO1xuICAgIC8qKlxuICAgICAqIHdhdGNoIHRoZSBjcmF0ZSBjaGFuZ2VzIGFuZCBidWlsZCBjb250aW51b3VzbHkgd2l0aCBgY2FyZ28td2F0Y2hgIGNyYXRlc1xuICAgICAqL1xuICAgIHdhdGNoPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBTcGFjZS1zZXBhcmF0ZWQgbGlzdCBvZiBmZWF0dXJlcyB0byBhY3RpdmF0ZVxuICAgICAqL1xuICAgIGZlYXR1cmVzPzogc3RyaW5nW107XG4gICAgLyoqXG4gICAgICogQWN0aXZhdGUgYWxsIGF2YWlsYWJsZSBmZWF0dXJlc1xuICAgICAqL1xuICAgIGFsbEZlYXR1cmVzPzogYm9vbGVhbjtcbiAgICAvKipcbiAgICAgKiBEbyBub3QgYWN0aXZhdGUgdGhlIGBkZWZhdWx0YCBmZWF0dXJlXG4gICAgICovXG4gICAgbm9EZWZhdWx0RmVhdHVyZXM/OiBib29sZWFuO1xufTtcbiIsImRlY2xhcmUgbW9kdWxlICdvYnVnJyB7XG4gICAgaW50ZXJmYWNlIERlYnVnZ2VyIHtcbiAgICAgICAgaW5mbzogdHlwZW9mIGNvbnNvbGUuZXJyb3I7XG4gICAgICAgIHdhcm46IHR5cGVvZiBjb25zb2xlLmVycm9yO1xuICAgICAgICBlcnJvcjogdHlwZW9mIGNvbnNvbGUuZXJyb3I7XG4gICAgfVxufVxuZXhwb3J0IGRlY2xhcmUgY29uc3QgZGVidWdGYWN0b3J5OiAobmFtZXNwYWNlOiBzdHJpbmcpID0+IGltcG9ydChcIm9idWdcIikuRGVidWdnZXI7XG5leHBvcnQgZGVjbGFyZSBjb25zdCBkZWJ1ZzogaW1wb3J0KFwib2J1Z1wiKS5EZWJ1Z2dlcjtcbiIsImV4cG9ydCB0eXBlIFBsYXRmb3JtID0gTm9kZUpTLlBsYXRmb3JtIHwgJ3dhc20nIHwgJ3dhc2knIHwgJ29wZW5oYXJtb255JztcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IFVOSVZFUlNBTF9UQVJHRVRTOiB7XG4gICAgcmVhZG9ubHkgJ3VuaXZlcnNhbC1hcHBsZS1kYXJ3aW4nOiByZWFkb25seSBbXCJhYXJjaDY0LWFwcGxlLWRhcndpblwiLCBcIng4Nl82NC1hcHBsZS1kYXJ3aW5cIl07XG59O1xuZXhwb3J0IGRlY2xhcmUgY29uc3QgQVZBSUxBQkxFX1RBUkdFVFM6IHJlYWRvbmx5IFtcImFhcmNoNjQtYXBwbGUtZGFyd2luXCIsIFwiYWFyY2g2NC1saW51eC1hbmRyb2lkXCIsIFwiYWFyY2g2NC11bmtub3duLWxpbnV4LWdudVwiLCBcImFhcmNoNjQtdW5rbm93bi1saW51eC1tdXNsXCIsIFwiYWFyY2g2NC11bmtub3duLWxpbnV4LW9ob3NcIiwgXCJhYXJjaDY0LXBjLXdpbmRvd3MtbXN2Y1wiLCBcIng4Nl82NC1hcHBsZS1kYXJ3aW5cIiwgXCJ4ODZfNjQtcGMtd2luZG93cy1tc3ZjXCIsIFwieDg2XzY0LXBjLXdpbmRvd3MtZ251XCIsIFwieDg2XzY0LXVua25vd24tbGludXgtZ251XCIsIFwieDg2XzY0LXVua25vd24tbGludXgtbXVzbFwiLCBcIng4Nl82NC11bmtub3duLWxpbnV4LW9ob3NcIiwgXCJ4ODZfNjQtdW5rbm93bi1mcmVlYnNkXCIsIFwiaTY4Ni1wYy13aW5kb3dzLW1zdmNcIiwgXCJhcm12Ny11bmtub3duLWxpbnV4LWdudWVhYmloZlwiLCBcImFybXY3LXVua25vd24tbGludXgtbXVzbGVhYmloZlwiLCBcImFybXY3LWxpbnV4LWFuZHJvaWRlYWJpXCIsIFwidW5pdmVyc2FsLWFwcGxlLWRhcndpblwiLCBcImxvb25nYXJjaDY0LXVua25vd24tbGludXgtZ251XCIsIFwicmlzY3Y2NGdjLXVua25vd24tbGludXgtZ251XCIsIFwicG93ZXJwYzY0bGUtdW5rbm93bi1saW51eC1nbnVcIiwgXCJzMzkweC11bmtub3duLWxpbnV4LWdudVwiLCBcIndhc20zMi13YXNpcDFcIiwgXCJ3YXNtMzItd2FzaXAxLXRocmVhZHNcIl07XG5leHBvcnQgdHlwZSBUYXJnZXRUcmlwbGUgPSAodHlwZW9mIEFWQUlMQUJMRV9UQVJHRVRTKVtudW1iZXJdO1xuZXhwb3J0IGRlY2xhcmUgY29uc3QgREVGQVVMVF9UQVJHRVRTOiByZWFkb25seSBbXCJ4ODZfNjQtYXBwbGUtZGFyd2luXCIsIFwiYWFyY2g2NC1hcHBsZS1kYXJ3aW5cIiwgXCJ4ODZfNjQtcGMtd2luZG93cy1tc3ZjXCIsIFwieDg2XzY0LXVua25vd24tbGludXgtZ251XCJdO1xuZXhwb3J0IGRlY2xhcmUgY29uc3QgVEFSR0VUX0xJTktFUjogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbnR5cGUgTm9kZUpTQXJjaCA9ICdhcm0nIHwgJ2FybTY0JyB8ICdpYTMyJyB8ICdsb29uZzY0JyB8ICdtaXBzJyB8ICdtaXBzZWwnIHwgJ3BwYycgfCAncHBjNjQnIHwgJ3Jpc2N2NjQnIHwgJ3MzOTAnIHwgJ3MzOTB4JyB8ICd4MzInIHwgJ3g2NCcgfCAndW5pdmVyc2FsJyB8ICd3YXNtMzInO1xuZXhwb3J0IGRlY2xhcmUgY29uc3QgTm9kZUFyY2hUb0NwdTogUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbmV4cG9ydCBkZWNsYXJlIGNvbnN0IFVuaUFyY2hzQnlQbGF0Zm9ybTogUGFydGlhbDxSZWNvcmQ8UGxhdGZvcm0sIE5vZGVKU0FyY2hbXT4+O1xuZXhwb3J0IGludGVyZmFjZSBUYXJnZXQge1xuICAgIHRyaXBsZTogc3RyaW5nO1xuICAgIHBsYXRmb3JtQXJjaEFCSTogc3RyaW5nO1xuICAgIHBsYXRmb3JtOiBQbGF0Zm9ybTtcbiAgICBhcmNoOiBOb2RlSlNBcmNoO1xuICAgIGFiaTogc3RyaW5nIHwgbnVsbDtcbn1cbmV4cG9ydCB0eXBlIFdhc2lGbGF2b3IgPSAnc2luZ2xlJyB8ICd0aHJlYWRzJztcbmV4cG9ydCBpbnRlcmZhY2UgV2FzaVRhcmdldCB7XG4gICAgY2Fub25pY2FsVHJpcGxlOiBzdHJpbmc7XG4gICAgZmxhdm9yOiBXYXNpRmxhdm9yO1xuICAgIHBsYXRmb3JtQXJjaEFCSTogc3RyaW5nO1xufVxuLyoqXG4gKiBSZXNvbHZlIGhpc3RvcmljYWwgV0FTSSBzcGVsbGluZ3MgdG8gb25lIGJ1aWxkIHRhcmdldCBhbmQgb25lIGFydGlmYWN0XG4gKiBpZGVudGl0eS4gYHdhc20zMi13YXNpYCBoaXN0b3JpY2FsbHkgcHJvZHVjZWQgdGhlIHRocmVhZGVkIHBhY2thZ2UsIHNvIGl0XG4gKiBtdXN0IG5ldmVyIGJlIGluZmVycmVkIGFzIHRocmVhZGxlc3MgbWVyZWx5IGJlY2F1c2UgaXRzIG5hbWUgbGFja3MgdGhlXG4gKiBgLXRocmVhZHNgIHN1ZmZpeC5cbiAqL1xuZXhwb3J0IGRlY2xhcmUgZnVuY3Rpb24gZ2V0V2FzaVRhcmdldCh0YXJnZXQ6IHN0cmluZyB8IFBpY2s8VGFyZ2V0LCAndHJpcGxlJz4pOiBXYXNpVGFyZ2V0IHwgdW5kZWZpbmVkO1xuZXhwb3J0IGRlY2xhcmUgZnVuY3Rpb24gd2FzaVRhcmdldEhhc1R