projen
Version:
CDK for software projects
204 lines • 26.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileBase = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const fs_1 = require("fs");
const path = __importStar(require("path"));
const _resolve_1 = require("./_resolve");
const common_1 = require("./common");
const component_1 = require("./component");
const projenrc_1 = require("./projenrc");
const util_1 = require("./util");
const constructs_1 = require("./util/constructs");
const diff_1 = require("./util/diff");
class FileBase extends component_1.Component {
static [JSII_RTTI_SYMBOL_1] = { fqn: "projen.FileBase", version: "0.103.12" };
/**
* The file path, relative to the project's outdir.
*/
path;
/**
* Indicates if the file should be read-only or read-write.
*/
readonly;
/**
* Indicates if the file should be marked as executable.
*/
executable;
/**
* Indicates if the file will be committed.
*/
committed;
/**
* The absolute path of this file.
*/
absolutePath;
_changed;
_previousContent;
_newContent;
shouldAddMarker;
/**
* The projen marker, used to identify files as projen-generated.
*
* Value is undefined if the project is being ejected.
*/
get marker() {
if (this.project.ejected || !this.shouldAddMarker) {
return undefined;
}
// `marker` is empty if project is being ejected or if explicitly disabled
const projenrc = projenrc_1.ProjenrcFile.of(this.project)?.filePath ?? common_1.DEFAULT_PROJEN_RC_JS_FILENAME;
return `${common_1.PROJEN_MARKER}. To modify, edit ${projenrc} and run "${this.project.projenCommand}".`;
}
constructor(scope, filePath, options = {}) {
const project = (0, constructs_1.findClosestProject)(scope, new.target.name);
const root = project.root;
const normalizedPath = path.normalize(filePath);
const projectPath = (0, util_1.normalizePersistedPath)(normalizedPath);
const absolutePath = path.resolve(project.outdir, projectPath);
const relativeProjectPath = path.relative(root.outdir, absolutePath);
const rootProjectPath = (0, util_1.normalizePersistedPath)(relativeProjectPath);
const autoId = `${new.target.name}@${projectPath}`;
// Before actually creating the file, ensure the file path is unique within the full project tree
// This is required because projects can create files inside their subprojects
if (root.tryFindFile(absolutePath) || scope.node.tryFindChild(autoId)) {
throw new Error(`There is already a file under ${rootProjectPath}`);
}
super(scope, autoId);
this.node.addMetadata("type", "file");
this.node.addMetadata("path", rootProjectPath);
this.readonly = !project.ejected && (options.readonly ?? true);
this.executable = options.executable ?? false;
this.path = projectPath;
this.absolutePath = absolutePath;
this.shouldAddMarker = options.marker ?? true;
const globPattern = `/${this.path}`;
this.committed = options.committed ?? project.commitGenerated ?? true;
if (this.committed && filePath !== ".gitattributes") {
project.annotateGenerated(`/${filePath}`);
}
const editGitignore = options.editGitignore ?? true;
if (editGitignore) {
this.project.addGitIgnore(`${this.committed ? "!" : ""}${globPattern}`);
}
else {
if (options.committed != null) {
throw new Error('"gitignore" is disabled, so it does not make sense to specify "committed"');
}
}
}
/**
* Writes the file to the project's output directory
*/
synthesize() {
const outdir = this.project.outdir;
const filePath = path.join(outdir, this.path);
const resolver = {
resolve: (obj, options) => (0, _resolve_1.resolve)(obj, options),
};
const content = this.synthesizeContent(resolver);
if (content === undefined) {
// remove file (if exists) and skip rest of synthesis
(0, fs_1.rmSync)(filePath, { force: true, recursive: true });
return;
}
// check if the file was changed.
const prev = (0, util_1.tryReadFileSync)(filePath);
this._previousContent = prev;
this._newContent = content;
const prevReadonly = !(0, util_1.isWritable)(filePath);
const successfulExecutableAssertion = (0, util_1.assertExecutablePermissions)(filePath, this.executable);
if (prev !== undefined &&
content === prev &&
prevReadonly === this.readonly &&
successfulExecutableAssertion) {
this.project.logger.verbose(`no change in ${filePath}`);
this._changed = false;
return;
}
(0, util_1.writeFile)(filePath, content, {
readonly: this.readonly,
executable: this.executable,
});
this.checkForProjenMarker();
this._changed = true;
}
/**
* For debugging, check whether a file was incorrectly generated with
* or without the projen marker. The projen marker does not *need* to be
* included on projen-generated files, but it's recommended since it signals
* that it probably should not be edited directly.
*/
checkForProjenMarker() {
const filePath = path.join(this.project.outdir, this.path);
const contents = (0, util_1.tryReadFileSync)(filePath);
const containsMarker = contents?.includes(common_1.PROJEN_MARKER);
if (this.marker && !containsMarker) {
this.project.logger.debug(`note: expected ${this.path} to contain marker but found none.`);
}
else if (!this.marker && containsMarker) {
this.project.logger.debug(`note: expected ${this.path} to not contain marker but found one anyway.`);
}
}
/**
* Indicates if the file has been changed during synthesis. This property is
* only available in `postSynthesize()` hooks. If this is `undefined`, the
* file has not been synthesized yet.
*/
get changed() {
return this._changed;
}
/**
* Returns a unified diff of the old and new file contents with context lines
* and hunk headers. Only available after synthesis.
*
* This is an expensive operation and should only be used on non time-critical
* code paths, like debug output.
*
* @param colorize Whether to colorize the diff output. @default false
* @param contextLines Number of context lines around changes. @default 3
* @returns the diff as an array of lines, or `undefined` if the file was
* not changed or has not been synthesized yet.
*/
diff(colorize = false, contextLines = 3) {
if (!this._changed) {
return undefined;
}
return (0, diff_1.unifiedDiff)(this._previousContent ?? "", this._newContent ?? "", colorize, contextLines);
}
}
exports.FileBase = FileBase;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9maWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwyQkFBNEI7QUFDNUIsMkNBQTZCO0FBRTdCLHlDQUFxQztBQUNyQyxxQ0FBd0U7QUFDeEUsMkNBQXdDO0FBQ3hDLHlDQUEwQztBQUMxQyxpQ0FNZ0I7QUFDaEIsa0RBQXVEO0FBQ3ZELHNDQUEwQztBQXdDMUMsTUFBc0IsUUFBUyxTQUFRLHFCQUFTOztJQUM5Qzs7T0FFRztJQUNhLElBQUksQ0FBUztJQUU3Qjs7T0FFRztJQUNJLFFBQVEsQ0FBVTtJQUV6Qjs7T0FFRztJQUNJLFVBQVUsQ0FBVTtJQUUzQjs7T0FFRztJQUNhLFNBQVMsQ0FBVTtJQUVuQzs7T0FFRztJQUNhLFlBQVksQ0FBUztJQUU3QixRQUFRLENBQVc7SUFDbkIsZ0JBQWdCLENBQVU7SUFDMUIsV0FBVyxDQUFVO0lBQ3JCLGVBQWUsQ0FBVTtJQUVqQzs7OztPQUlHO0lBQ0gsSUFBVyxNQUFNO1FBQ2YsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNsRCxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDO1FBRUQsMEVBQTBFO1FBQzFFLE1BQU0sUUFBUSxHQUNaLHVCQUFZLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxRQUFRLElBQUksc0NBQTZCLENBQUM7UUFDM0UsT0FBTyxHQUFHLHNCQUFhLHFCQUFxQixRQUFRLGFBQWEsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLElBQUksQ0FBQztJQUNsRyxDQUFDO0lBRUQsWUFDRSxLQUFpQixFQUNqQixRQUFnQixFQUNoQixVQUEyQixFQUFFO1FBRTdCLE1BQU0sT0FBTyxHQUFHLElBQUEsK0JBQWtCLEVBQUMsS0FBSyxFQUFFLEdBQUcsQ0FB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T0FBTyxJQUFBLGtCQUFXLEVBQ2hCLElBQUksQ0FBQyxnQkFBZ0IsSUFBSSxFQUFFLEVBQzNCLElBQUksQ0FBQyxXQUFXLElBQUksRUFBRSxFQUN0QixRQUFRLEVBQ1IsWUFBWSxDQUNiLENBQUM7SUFDSixDQUFDOztBQTFNSCw0QkEyTUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBybVN5bmMgfSBmcm9tIFwiZnNcIjtcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB0eXBlIHsgSUNvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyByZXNvbHZlIH0gZnJvbSBcIi4vX3Jlc29sdmVcIjtcbmltcG9ydCB7IFBST0pFTl9NQVJLRVIsIERFRkFVTFRfUFJPSkVOX1JDX0pTX0ZJTEVOQU1FIH0gZnJvbSBcIi4vY29tbW9uXCI7XG5pbXBvcnQgeyBDb21wb25lbnQgfSBmcm9tIFwiLi9jb21wb25lbnRcIjtcbmltcG9ydCB7IFByb2plbnJjRmlsZSB9IGZyb20gXCIuL3Byb2plbnJjXCI7XG5pbXBvcnQge1xuICBhc3NlcnRFeGVjdXRhYmxlUGVybWlzc2lvbnMsXG4gIGlzV3JpdGFibGUsXG4gIG5vcm1hbGl6ZVBlcnNpc3RlZFBhdGgsXG4gIHRyeVJlYWRGaWxlU3luYyxcbiAgd3JpdGVGaWxlLFxufSBmcm9tIFwiLi91dGlsXCI7XG5pbXBvcnQgeyBmaW5kQ2xvc2VzdFByb2plY3QgfSBmcm9tIFwiLi91dGlsL2NvbnN0cnVjdHNcIjtcbmltcG9ydCB7IHVuaWZpZWREaWZmIH0gZnJvbSBcIi4vdXRpbC9kaWZmXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZUJhc2VPcHRpb25zIHtcbiAgLyoqXG4gICAqIEluZGljYXRlcyB3aGV0aGVyIHRoaXMgZmlsZSBzaG91bGQgYmUgY29tbWl0dGVkIHRvIGdpdCBvciBpZ25vcmVkLiBCeVxuICAgKiBkZWZhdWx0LCBhbGwgZ2VuZXJhdGVkIGZpbGVzIGFyZSBjb21taXR0ZWQgYW5kIGFudGktdGFtcGVyIGlzIHVzZWQgdG9cbiAgICogcHJvdGVjdCBhZ2FpbnN0IG1hbnVhbCBtb2RpZmljYXRpb25zLlxuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBjb21taXR0ZWQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIHByb2plY3QncyAuZ2l0aWdub3JlIGZpbGVcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgZWRpdEdpdGlnbm9yZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGdlbmVyYXRlZCBmaWxlIHNob3VsZCBiZSByZWFkb25seS5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgcmVhZG9ubHk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBnZW5lcmF0ZWQgZmlsZSBzaG91bGQgYmUgbWFya2VkIGFzIGV4ZWN1dGFibGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBleGVjdXRhYmxlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQWRkcyB0aGUgcHJvamVuIG1hcmtlciB0byB0aGUgZmlsZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBtYXJrZXIgd2lsbCBiZSBpbmNsdWRlZCBhcyBsb25nIGFzIHRoZSBwcm9qZWN0IGlzIG5vdCBlamVjdGVkXG4gICAqL1xuICByZWFkb25seSBtYXJrZXI/OiBib29sZWFuO1xufVxuXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRmlsZUJhc2UgZXh0ZW5kcyBDb21wb25lbnQge1xuICAvKipcbiAgICogVGhlIGZpbGUgcGF0aCwgcmVsYXRpdmUgdG8gdGhlIHByb2plY3QncyBvdXRkaXIuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcGF0aDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGZpbGUgc2hvdWxkIGJlIHJlYWQtb25seSBvciByZWFkLXdyaXRlLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGZpbGUgc2hvdWxkIGJlIG1hcmtlZCBhcyBleGVjdXRhYmxlLlxuICAgKi9cbiAgcHVibGljIGV4ZWN1dGFibGU6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgZmlsZSB3aWxsIGJlIGNvbW1pdHRlZC5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBjb21taXR0ZWQ6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBhYnNvbHV0ZSBwYXRoIG9mIHRoaXMgZmlsZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBhYnNvbHV0ZVBhdGg6IHN0cmluZztcblxuICBwcml2YXRlIF9jaGFuZ2VkPzogYm9vbGVhbjtcbiAgcHJpdmF0ZSBfcHJldmlvdXNDb250ZW50Pzogc3RyaW5nO1xuICBwcml2YXRlIF9uZXdDb250ZW50Pzogc3RyaW5nO1xuICBwcml2YXRlIHNob3VsZEFkZE1hcmtlcjogYm9vbGVhbjtcblxuICAvKipcbiAgICogVGhlIHByb2plbiBtYXJrZXIsIHVzZWQgdG8gaWRlbnRpZnkgZmlsZXMgYXMgcHJvamVuLWdlbmVyYXRlZC5cbiAgICpcbiAgICogVmFsdWUgaXMgdW5kZWZpbmVkIGlmIHRoZSBwcm9qZWN0IGlzIGJlaW5nIGVqZWN0ZWQuXG4gICAqL1xuICBwdWJsaWMgZ2V0IG1hcmtlcigpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICh0aGlzLnByb2plY3QuZWplY3RlZCB8fCAhdGhpcy5zaG91bGRBZGRNYXJrZXIpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gYG1hcmtlcmAgaXMgZW1wdHkgaWYgcHJvamVjdCBpcyBiZWluZyBlamVjdGVkIG9yIGlmIGV4cGxpY2l0bHkgZGlzYWJsZWRcbiAgICBjb25zdCBwcm9qZW5yYyA9XG4gICAgICBQcm9qZW5yY0ZpbGUub2YodGhpcy5wcm9qZWN0KT8uZmlsZVBhdGggPz8gREVGQVVMVF9QUk9KRU5fUkNfSlNfRklMRU5BTUU7XG4gICAgcmV0dXJuIGAke1BST0pFTl9NQVJLRVJ9LiBUbyBtb2RpZnksIGVkaXQgJHtwcm9qZW5yY30gYW5kIHJ1biBcIiR7dGhpcy5wcm9qZWN0LnByb2plbkNvbW1hbmR9XCIuYDtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHNjb3BlOiBJQ29uc3RydWN0LFxuICAgIGZpbGVQYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9uczogRmlsZUJhc2VPcHRpb25zID0ge30sXG4gICkge1xuICAgIGNvbnN0IHByb2plY3QgPSBmaW5kQ2xvc2VzdFByb2plY3Qoc2NvcGUsIG5ldy50YXJnZXQubmFtZSk7XG4gICAgY29uc3Qgcm9vdCA9IHByb2plY3Qucm9vdDtcbiAgICBjb25zdCBub3JtYWxpemVkUGF0aCA9IHBhdGgubm9ybWFsaXplKGZpbGVQYXRoKTtcbiAgICBjb25zdCBwcm9qZWN0UGF0aCA9IG5vcm1hbGl6ZVBlcnNpc3RlZFBhdGgobm9ybWFsaXplZFBhdGgpO1xuICAgIGNvbnN0IGFic29sdXRlUGF0aCA9IHBhdGgucmVzb2x2ZShwcm9qZWN0Lm91dGRpciwgcHJvamVjdFBhdGgpO1xuICAgIGNvbnN0IHJlbGF0aXZlUHJvamVjdFBhdGggPSBwYXRoLnJlbGF0aXZlKHJvb3Qub3V0ZGlyLCBhYnNvbHV0ZVBhdGgpO1xuICAgIGNvbnN0IHJvb3RQcm9qZWN0UGF0aCA9IG5vcm1hbGl6ZVBlcnNpc3RlZFBhdGgocmVsYXRpdmVQcm9qZWN0UGF0aCk7XG4gICAgY29uc3QgYXV0b0lkID0gYCR7bmV3LnRhcmdldC5uYW1lfUAke3Byb2plY3RQYXRofWA7XG5cbiAgICAvLyBCZWZvcmUgYWN0dWFsbHkgY3JlYXRpbmcgdGhlIGZpbGUsIGVuc3VyZSB0aGUgZmlsZSBwYXRoIGlzIHVuaXF1ZSB3aXRoaW4gdGhlIGZ1bGwgcHJvamVjdCB0cmVlXG4gICAgLy8gVGhpcyBpcyByZXF1aXJlZCBiZWNhdXNlIHByb2plY3RzIGNhbiBjcmVhdGUgZmlsZXMgaW5zaWRlIHRoZWlyIHN1YnByb2plY3RzXG4gICAgaWYgKHJvb3QudHJ5RmluZEZpbGUoYWJzb2x1dGVQYXRoKSB8fCBzY29wZS5ub2RlLnRyeUZpbmRDaGlsZChhdXRvSWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZXJlIGlzIGFscmVhZHkgYSBmaWxlIHVuZGVyICR7cm9vdFByb2plY3RQYXRofWApO1xuICAgIH1cblxuICAgIHN1cGVyKHNjb3BlLCBhdXRvSWQpO1xuICAgIHRoaXMubm9kZS5hZGRNZXRhZGF0YShcInR5cGVcIiwgXCJmaWxlXCIpO1xuICAgIHRoaXMubm9kZS5hZGRNZXRhZGF0YShcInBhdGhcIiwgcm9vdFByb2plY3RQYXRoKTtcblxuICAgIHRoaXMucmVhZG9ubHkgPSAhcHJvamVjdC5lamVjdGVkICYmIChvcHRpb25zLnJlYWRvbmx5ID8/IHRydWUpO1xuICAgIHRoaXMuZXhlY3V0YWJsZSA9IG9wdGlvbnMuZXhlY3V0YWJsZSA/PyBmYWxzZTtcbiAgICB0aGlzLnBhdGggPSBwcm9qZWN0UGF0aDtcbiAgICB0aGlzLmFic29sdXRlUGF0aCA9IGFic29sdXRlUGF0aDtcbiAgICB0aGlzLnNob3VsZEFkZE1hcmtlciA9IG9wdGlvbnMubWFya2VyID8/IHRydWU7XG5cbiAgICBjb25zdCBnbG9iUGF0dGVybiA9IGAvJHt0aGlzLnBhdGh9YDtcbiAgICB0aGlzLmNvbW1pdHRlZCA9IG9wdGlvbnMuY29tbWl0dGVkID8/IHByb2plY3QuY29tbWl0R2VuZXJhdGVkID8/IHRydWU7XG4gICAgaWYgKHRoaXMuY29tbWl0dGVkICYmIGZpbGVQYXRoICE9PSBcIi5naXRhdHRyaWJ1dGVzXCIpIHtcbiAgICAgIHByb2plY3QuYW5ub3RhdGVHZW5lcmF0ZWQoYC8ke2ZpbGVQYXRofWApO1xuICAgIH1cbiAgICBjb25zdCBlZGl0R2l0aWdub3JlID0gb3B0aW9ucy5lZGl0R2l0aWdub3JlID8/IHRydWU7XG4gICAgaWYgKGVkaXRHaXRpZ25vcmUpIHtcbiAgICAgIHRoaXMucHJvamVjdC5hZGRHaXRJZ25vcmUoYCR7dGhpcy5jb21taXR0ZWQgPyBcIiFcIiA6IFwiXCJ9JHtnbG9iUGF0dGVybn1gKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKG9wdGlvbnMuY29tbWl0dGVkICE9IG51bGwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICdcImdpdGlnbm9yZVwiIGlzIGRpc2FibGVkLCBzbyBpdCBkb2VzIG5vdCBtYWtlIHNlbnNlIHRvIHNwZWNpZnkgXCJjb21taXR0ZWRcIicsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEltcGxlbWVudGVkIGJ5IGRlcml2ZWQgY2xhc3NlcyBhbmQgcmV0dXJucyB0aGUgY29udGVudHMgb2YgdGhlIGZpbGUgdG9cbiAgICogZW1pdC5cbiAgICogQHBhcmFtIHJlc29sdmVyIENhbGwgYHJlc29sdmVyLnJlc29sdmUob2JqKWAgb24gYW55IG9iamVjdHMgaW4gb3JkZXIgdG9cbiAgICogcmVzb2x2ZSB0b2tlbiBmdW5jdGlvbnMuXG4gICAqIEByZXR1cm5zIHRoZSBjb250ZW50IHRvIHN5bnRoZXNpemUgb3IgdW5kZWZpbmVkIHRvIHNraXAgdGhlIGZpbGVcbiAgICovXG4gIHByb3RlY3RlZCBhYnN0cmFjdCBzeW50aGVzaXplQ29udGVudChyZXNvbHZlcjogSVJlc29sdmVyKTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBXcml0ZXMgdGhlIGZpbGUgdG8gdGhlIHByb2plY3QncyBvdXRwdXQgZGlyZWN0b3J5XG4gICAqL1xuICBwdWJsaWMgc3ludGhlc2l6ZSgpIHtcbiAgICBjb25zdCBvdXRkaXIgPSB0aGlzLnByb2plY3Qub3V0ZGlyO1xuICAgIGNvbnN0IGZpbGVQYXRoID0gcGF0aC5qb2luKG91dGRpciwgdGhpcy5wYXRoKTtcbiAgICBjb25zdCByZXNvbHZlcjogSVJlc29sdmVyID0ge1xuICAgICAgcmVzb2x2ZTogKG9iaiwgb3B0aW9ucykgPT4gcmVzb2x2ZShvYmosIG9wdGlvbnMpLFxuICAgIH07XG4gICAgY29uc3QgY29udGVudCA9IHRoaXMuc3ludGhlc2l6ZUNvbnRlbnQocmVzb2x2ZXIpO1xuICAgIGlmIChjb250ZW50ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIC8vIHJlbW92ZSBmaWxlIChpZiBleGlzdHMpIGFuZCBza2lwIHJlc3Qgb2Ygc3ludGhlc2lzXG4gICAgICBybVN5bmMoZmlsZVBhdGgsIHsgZm9yY2U6IHRydWUsIHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBjaGVjayBpZiB0aGUgZmlsZSB3YXMgY2hhbmdlZC5cbiAgICBjb25zdCBwcmV2ID0gdHJ5UmVhZEZpbGVTeW5jKGZpbGVQYXRoKTtcbiAgICB0aGlzLl9wcmV2aW91c0NvbnRlbnQgPSBwcmV2O1xuICAgIHRoaXMuX25ld0NvbnRlbnQgPSBjb250ZW50O1xuICAgIGNvbnN0IHByZXZSZWFkb25seSA9ICFpc1dyaXRhYmxlKGZpbGVQYXRoKTtcbiAgICBjb25zdCBzdWNjZXNzZnVsRXhlY3V0YWJsZUFzc2VydGlvbiA9IGFzc2VydEV4ZWN1dGFibGVQZXJtaXNzaW9ucyhcbiAgICAgIGZpbGVQYXRoLFxuICAgICAgdGhpcy5leGVjdXRhYmxlLFxuICAgICk7XG4gICAgaWYgKFxuICAgICAgcHJldiAhPT0gdW5kZWZpbmVkICYmXG4gICAgICBjb250ZW50ID09PSBwcmV2ICYmXG4gICAgICBwcmV2UmVhZG9ubHkgPT09IHRoaXMucmVhZG9ubHkgJiZcbiAgICAgIHN1Y2Nlc3NmdWxFeGVjdXRhYmxlQXNzZXJ0aW9uXG4gICAgKSB7XG4gICAgICB0aGlzLnByb2plY3QubG9nZ2VyLnZlcmJvc2UoYG5vIGNoYW5nZSBpbiAke2ZpbGVQYXRofWApO1xuICAgICAgdGhpcy5fY2hhbmdlZCA9IGZhbHNlO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHdyaXRlRmlsZShmaWxlUGF0aCwgY29udGVudCwge1xuICAgICAgcmVhZG9ubHk6IHRoaXMucmVhZG9ubHksXG4gICAgICBleGVjdXRhYmxlOiB0aGlzLmV4ZWN1dGFibGUsXG4gICAgfSk7XG5cbiAgICB0aGlzLmNoZWNrRm9yUHJvamVuTWFya2VyKCk7XG5cbiAgICB0aGlzLl9jaGFuZ2VkID0gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3IgZGVidWdnaW5nLCBjaGVjayB3aGV0aGVyIGEgZmlsZSB3YXMgaW5jb3JyZWN0bHkgZ2VuZXJhdGVkIHdpdGhcbiAgICogb3Igd2l0aG91dCB0aGUgcHJvamVuIG1hcmtlci4gVGhlIHByb2plbiBtYXJrZXIgZG9lcyBub3QgKm5lZWQqIHRvIGJlXG4gICAqIGluY2x1ZGVkIG9uIHByb2plbi1nZW5lcmF0ZWQgZmlsZXMsIGJ1dCBpdCdzIHJlY29tbWVuZGVkIHNpbmNlIGl0IHNpZ25hbHNcbiAgICogdGhhdCBpdCBwcm9iYWJseSBzaG91bGQgbm90IGJlIGVkaXRlZCBkaXJlY3RseS5cbiAgICovXG4gIHByaXZhdGUgY2hlY2tGb3JQcm9qZW5NYXJrZXIoKSB7XG4gICAgY29uc3QgZmlsZVBhdGggPSBwYXRoLmpvaW4odGhpcy5wcm9qZWN0Lm91dGRpciwgdGhpcy5wYXRoKTtcbiAgICBjb25zdCBjb250ZW50cyA9IHRyeVJlYWRGaWxlU3luYyhmaWxlUGF0aCk7XG4gICAgY29uc3QgY29udGFpbnNNYXJrZXIgPSBjb250ZW50cz8uaW5jbHVkZXMoUFJPSkVOX01BUktFUik7XG4gICAgaWYgKHRoaXMubWFya2VyICYmICFjb250YWluc01hcmtlcikge1xuICAgICAgdGhpcy5wcm9qZWN0LmxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgYG5vdGU6IGV4cGVjdGVkICR7dGhpcy5wYXRofSB0byBjb250YWluIG1hcmtlciBidXQgZm91bmQgbm9uZS5gLFxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKCF0aGlzLm1hcmtlciAmJiBjb250YWluc01hcmtlcikge1xuICAgICAgdGhpcy5wcm9qZWN0LmxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgYG5vdGU6IGV4cGVjdGVkICR7dGhpcy5wYXRofSB0byBub3QgY29udGFpbiBtYXJrZXIgYnV0IGZvdW5kIG9uZSBhbnl3YXkuYCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgZmlsZSBoYXMgYmVlbiBjaGFuZ2VkIGR1cmluZyBzeW50aGVzaXMuIFRoaXMgcHJvcGVydHkgaXNcbiAgICogb25seSBhdmFpbGFibGUgaW4gYHBvc3RTeW50aGVzaXplKClgIGhvb2tzLiBJZiB0aGlzIGlzIGB1bmRlZmluZWRgLCB0aGVcbiAgICogZmlsZSBoYXMgbm90IGJlZW4gc3ludGhlc2l6ZWQgeWV0LlxuICAgKi9cbiAgcHVibGljIGdldCBjaGFuZ2VkKCk6IGJvb2xlYW4gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9jaGFuZ2VkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSB1bmlmaWVkIGRpZmYgb2YgdGhlIG9sZCBhbmQgbmV3IGZpbGUgY29udGVudHMgd2l0aCBjb250ZXh0IGxpbmVzXG4gICAqIGFuZCBodW5rIGhlYWRlcnMuIE9ubHkgYXZhaWxhYmxlIGFmdGVyIHN5bnRoZXNpcy5cbiAgICpcbiAgICogVGhpcyBpcyBhbiBleHBlbnNpdmUgb3BlcmF0aW9uIGFuZCBzaG91bGQgb25seSBiZSB1c2VkIG9uIG5vbiB0aW1lLWNyaXRpY2FsXG4gICAqIGNvZGUgcGF0aHMsIGxpa2UgZGVidWcgb3V0cHV0LlxuICAgKlxuICAgKiBAcGFyYW0gY29sb3JpemUgV2hldGhlciB0byBjb2xvcml6ZSB0aGUgZGlmZiBvdXRwdXQuIEBkZWZhdWx0IGZhbHNlXG4gICAqIEBwYXJhbSBjb250ZXh0TGluZXMgTnVtYmVyIG9mIGNvbnRleHQgbGluZXMgYXJvdW5kIGNoYW5nZXMuIEBkZWZhdWx0IDNcbiAgICogQHJldHVybnMgdGhlIGRpZmYgYXMgYW4gYXJyYXkgb2YgbGluZXMsIG9yIGB1bmRlZmluZWRgIGlmIHRoZSBmaWxlIHdhc1xuICAgKiBub3QgY2hhbmdlZCBvciBoYXMgbm90IGJlZW4gc3ludGhlc2l6ZWQgeWV0LlxuICAgKi9cbiAgcHVibGljIGRpZmYoY29sb3JpemUgPSBmYWxzZSwgY29udGV4dExpbmVzID0gMyk6IHN0cmluZ1tdIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXRoaXMuX2NoYW5nZWQpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHVuaWZpZWREaWZmKFxuICAgICAgdGhpcy5fcHJldmlvdXNDb250ZW50ID8/IFwiXCIsXG4gICAgICB0aGlzLl9uZXdDb250ZW50ID8/IFwiXCIsXG4gICAgICBjb2xvcml6ZSxcbiAgICAgIGNvbnRleHRMaW5lcyxcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogQVBJIGZvciByZXNvbHZpbmcgdG9rZW5zIHdoZW4gc3ludGhlc2l6aW5nIGZpbGUgY29udGVudC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJUmVzb2x2ZXIge1xuICAvKipcbiAgICogR2l2ZW4gYSB2YWx1ZSAob2JqZWN0L3N0cmluZy9hcnJheS93aGF0ZXZlciwgbG9va3MgdXAgYW55IGZ1bmN0aW9ucyBpbnNpZGVcbiAgICogdGhlIG9iamVjdCBhbmQgcmV0dXJucyBhbiBvYmplY3Qgd2hlcmUgYWxsIGZ1bmN0aW9ucyBhcmUgY2FsbGVkLlxuICAgKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRvIHJlc29sdmVcbiAgICogQHBhY2thZ2Ugb3B0aW9ucyBSZXNvbHZlIG9wdGlvbnNcbiAgICovXG4gIHJlc29sdmUodmFsdWU6IGFueSwgb3B0aW9ucz86IFJlc29sdmVPcHRpb25zKTogYW55O1xufVxuXG4vKipcbiAqIFJlc29sdmUgb3B0aW9ucy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBPbWl0cyBlbXB0eSBhcnJheXMgYW5kIG9iamVjdHMuXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBvbWl0RW1wdHk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBDb250ZXh0IGFyZ3VtZW50cy5cbiAgICogQGRlZmF1bHQgW11cbiAgICovXG4gIHJlYWRvbmx5IGFyZ3M/OiBhbnlbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJUmVzb2x2YWJsZSB7XG4gIC8qKlxuICAgKiBSZXNvbHZlcyBhbmQgcmV0dXJucyBjb250ZW50LlxuICAgKi9cbiAgdG9KU09OKCk6IGFueTtcbn1cbiJdfQ==