@aws-cdk/aws-iam
Version:
CDK routines for easily assigning correct and minimal IAM permissions
251 lines • 31.1 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PolicyDocument = void 0;
const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const cdk = require("@aws-cdk/core");
const cxapi = require("@aws-cdk/cx-api");
const policy_statement_1 = require("./policy-statement");
const merge_statements_1 = require("./private/merge-statements");
const postprocess_policy_document_1 = require("./private/postprocess-policy-document");
/**
* A PolicyDocument is a collection of statements
*/
class PolicyDocument {
constructor(props = {}) {
this.statements = new Array();
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyDocumentProps(props);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, PolicyDocument);
}
throw error;
}
this.creationStack = cdk.captureStackTrace();
this.autoAssignSids = !!props.assignSids;
this.minimize = props.minimize;
this.addStatements(...props.statements || []);
}
/**
* Creates a new PolicyDocument based on the object provided.
* This will accept an object created from the `.toJSON()` call
* @param obj the PolicyDocument in object form.
*/
static fromJson(obj) {
const newPolicyDocument = new PolicyDocument();
const statement = obj.Statement ?? [];
if (statement && !Array.isArray(statement)) {
throw new Error('Statement must be an array');
}
newPolicyDocument.addStatements(...obj.Statement.map((s) => policy_statement_1.PolicyStatement.fromJson(s)));
return newPolicyDocument;
}
resolve(context) {
this._maybeMergeStatements(context.scope);
// In the previous implementation of 'merge', sorting of actions/resources on
// a statement always happened, even on singular statements. In the new
// implementation of 'merge', sorting only happens when actually combining 2
// statements. This affects all test snapshots, so we need to put in mechanisms
// to avoid having to update all snapshots.
//
// To do sorting in a way compatible with the previous implementation of merging,
// (so we don't have to update snapshots) do it after rendering, but only when
// merging is enabled.
const sort = this.shouldMerge(context.scope);
context.registerPostProcessor(new postprocess_policy_document_1.PostProcessPolicyDocument(this.autoAssignSids, sort));
return this.render();
}
/**
* Whether the policy document contains any statements.
*/
get isEmpty() {
return this.statements.length === 0;
}
/**
* The number of statements already added to this policy.
* Can be used, for example, to generate unique "sid"s within the policy.
*/
get statementCount() {
return this.statements.length;
}
/**
* Adds a statement to the policy document.
*
* @param statement the statement to add.
*/
addStatements(...statement) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_iam_PolicyStatement(statement);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.addStatements);
}
throw error;
}
this.statements.push(...statement);
}
/**
* Encode the policy document as a string
*/
toString() {
return cdk.Token.asString(this, {
displayHint: 'PolicyDocument',
});
}
/**
* JSON-ify the document
*
* Used when JSON.stringify() is called
*/
toJSON() {
return this.render();
}
/**
* Validate that all policy statements in the policy document satisfies the
* requirements for any policy.
*
* @see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policies-json
*
* @returns An array of validation error messages, or an empty array if the document is valid.
*/
validateForAnyPolicy() {
const errors = new Array();
for (const statement of this.statements) {
errors.push(...statement.validateForAnyPolicy());
}
return errors;
}
/**
* Validate that all policy statements in the policy document satisfies the
* requirements for a resource-based policy.
*
* @see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policies-json
*
* @returns An array of validation error messages, or an empty array if the document is valid.
*/
validateForResourcePolicy() {
const errors = new Array();
for (const statement of this.statements) {
errors.push(...statement.validateForResourcePolicy());
}
return errors;
}
/**
* Validate that all policy statements in the policy document satisfies the
* requirements for an identity-based policy.
*
* @see https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#access_policies-json
*
* @returns An array of validation error messages, or an empty array if the document is valid.
*/
validateForIdentityPolicy() {
const errors = new Array();
for (const statement of this.statements) {
errors.push(...statement.validateForIdentityPolicy());
}
return errors;
}
/**
* Perform statement merging (if enabled and not done yet)
*
* @internal
*/
_maybeMergeStatements(scope) {
if (this.shouldMerge(scope)) {
const result = merge_statements_1.mergeStatements(scope, this.statements, false);
this.statements.splice(0, this.statements.length, ...result.mergedStatements);
}
}
/**
* Split the statements of the PolicyDocument into multiple groups, limited by their size
*
* We do a round of size-limited merging first (making sure to not produce statements too
* large to fit into standalone policies), so that we can most accurately estimate total
* policy size. Another final round of minimization will be done just before rendering to
* end up with minimal policies that look nice to humans.
*
* Return a map of the final set of policy documents, mapped to the ORIGINAL (pre-merge)
* PolicyStatements that ended up in the given PolicyDocument.
*
* @internal
*/
_splitDocument(scope, selfMaximumSize, splitMaximumSize) {
const self = this;
const newDocs = [];
// Maps final statements to original statements
let statementsToOriginals = new Map(this.statements.map(s => [s, [s]]));
if (this.shouldMerge(scope)) {
const result = merge_statements_1.mergeStatements(scope, this.statements, true);
this.statements.splice(0, this.statements.length, ...result.mergedStatements);
statementsToOriginals = result.originsMap;
}
const sizeOptions = policy_statement_1.deriveEstimateSizeOptions(scope);
// Cache statement sizes to avoid recomputing them based on the fields
const statementSizes = new Map(this.statements.map(s => [s, s._estimateSize(sizeOptions)]));
// Keep some size counters so we can avoid recomputing them based on the statements in each
let selfSize = 0;
const polSizes = new Map();
// Getter with a default to save some syntactic noise
const polSize = (x) => polSizes.get(x) ?? 0;
let i = 0;
while (i < this.statements.length) {
const statement = this.statements[i];
const statementSize = statementSizes.get(statement) ?? 0;
if (selfSize + statementSize < selfMaximumSize) {
// Fits in self
selfSize += statementSize;
i++;
continue;
}
// Split off to new PolicyDocument. Find the PolicyDocument we can add this to,
// or add a fresh one.
const addToDoc = findDocWithSpace(statementSize);
addToDoc.addStatements(statement);
polSizes.set(addToDoc, polSize(addToDoc) + statementSize);
this.statements.splice(i, 1);
}
// Return the set of all policy document and original statements
const ret = new Map();
ret.set(this, this.statements.flatMap(s => statementsToOriginals.get(s) ?? [s]));
for (const newDoc of newDocs) {
ret.set(newDoc, newDoc.statements.flatMap(s => statementsToOriginals.get(s) ?? [s]));
}
return ret;
function findDocWithSpace(size) {
let j = 0;
while (j < newDocs.length && polSize(newDocs[j]) + size > splitMaximumSize) {
j++;
}
if (j < newDocs.length) {
return newDocs[j];
}
const newDoc = new PolicyDocument({
assignSids: self.autoAssignSids,
minimize: self.minimize,
});
newDocs.push(newDoc);
return newDoc;
}
}
render() {
if (this.isEmpty) {
return undefined;
}
const doc = {
Statement: this.statements.map(s => s.toStatementJson()),
Version: '2012-10-17',
};
return doc;
}
shouldMerge(scope) {
return this.minimize ?? cdk.FeatureFlags.of(scope).isEnabled(cxapi.IAM_MINIMIZE_POLICIES) ?? false;
}
}
exports.PolicyDocument = PolicyDocument;
_a = JSII_RTTI_SYMBOL_1;
PolicyDocument[_a] = { fqn: "@aws-cdk/aws-iam.PolicyDocument", version: "1.204.0" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9saWN5LWRvY3VtZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicG9saWN5LWRvY3VtZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHFDQUFxQztBQUVyQyx5Q0FBeUM7QUFDekMseURBQWdGO0FBQ2hGLGlFQUE2RDtBQUM3RCx1RkFBa0Y7QUF1Q2xGOztHQUVHO0FBQ0gsTUFBYSxjQUFjO0lBc0J6QixZQUFZLFFBQTZCLEVBQUU7UUFKMUIsZUFBVSxHQUFHLElBQUksS0FBSyxFQUFtQixDQUFDOzs7Ozs7K0NBbEJoRCxjQUFjOzs7O1FBdUJ2QixJQUFJLENBQUMsYUFBYSxHQUFHLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQzdDLElBQUksQ0FBQyxjQUFjLEdBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUM7UUFDekMsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxDQUFDO1FBRS9CLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxLQUFLLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0tBQy9DO0lBMUJEOzs7O09BSUc7SUFDSSxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQVE7UUFDN0IsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLGNBQWMsRUFBRSxDQUFDO1FBQy9DLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxTQUFTLElBQUksRUFBRSxDQUFDO1FBQ3RDLElBQUksU0FBUyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRTtZQUMxQyxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7U0FDL0M7UUFDRCxpQkFBaUIsQ0FBQyxhQUFhLENBQUMsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsa0NBQWUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFD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LENBQUMsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLHFCQUFxQixDQUFDLElBQUksS0FBSyxDQUFDO0tBQ3BHOztBQXRQSCx3Q0F1UEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjZGsgZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgeyBJQ29uc3RydWN0IH0gZnJvbSAnQGF3cy1jZGsvY29yZSc7XG5pbXBvcnQgKiBhcyBjeGFwaSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHsgUG9saWN5U3RhdGVtZW50LCBkZXJpdmVFc3RpbWF0ZVNpemVPcHRpb25zIH0gZnJvbSAnLi9wb2xpY3ktc3RhdGVtZW50JztcbmltcG9ydCB7IG1lcmdlU3RhdGVtZW50cyB9IGZyb20gJy4vcHJpdmF0ZS9tZXJnZS1zdGF0ZW1lbnRzJztcbmltcG9ydCB7IFBvc3RQcm9jZXNzUG9saWN5RG9jdW1lbnQgfSBmcm9tICcuL3ByaXZhdGUvcG9zdHByb2Nlc3MtcG9saWN5LWRvY3VtZW50JztcblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBhIG5ldyBQb2xpY3lEb2N1bWVudFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBvbGljeURvY3VtZW50UHJvcHMge1xuICAvKipcbiAgICogQXV0b21hdGljYWxseSBhc3NpZ24gU3RhdGVtZW50IElkcyB0byBhbGwgc3RhdGVtZW50c1xuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgYXNzaWduU2lkcz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEluaXRpYWwgc3RhdGVtZW50cyB0byBhZGQgdG8gdGhlIHBvbGljeSBkb2N1bWVudFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHN0YXRlbWVudHNcbiAgICovXG4gIHJlYWRvbmx5IHN0YXRlbWVudHM/OiBQb2xpY3lTdGF0ZW1lbnRbXTtcblxuICAvKipcbiAgICogVHJ5IHRvIG1pbmltaXplIHRoZSBwb2xpY3kgYnkgbWVyZ2luZyBzdGF0ZW1lbnRzXG4gICAqXG4gICAqIFRvIGF2b2lkIG92ZXJydW5uaW5nIHRoZSBtYXhpbXVtIHBvbGljeSBzaXplLCBjb21iaW5lIHN0YXRlbWVudHMgaWYgdGhleSBwcm9kdWNlXG4gICAqIHRoZSBzYW1lIHJlc3VsdC4gTWVyZ2luZyBoYXBwZW5zIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIHJ1bGVzOlxuICAgKlxuICAgKiAtIFRoZSBFZmZlY3Qgb2YgYm90aCBzdGF0ZW1lbnRzIGlzIHRoZSBzYW1lXG4gICAqIC0gTmVpdGhlciBvZiB0aGUgc3RhdGVtZW50cyBoYXZlIGEgJ1NpZCdcbiAgICogLSBDb21iaW5lIFByaW5jaXBhbHMgaWYgdGhlIHJlc3Qgb2YgdGhlIHN0YXRlbWVudCBpcyBleGFjdGx5IHRoZSBzYW1lLlxuICAgKiAtIENvbWJpbmUgUmVzb3VyY2VzIGlmIHRoZSByZXN0IG9mIHRoZSBzdGF0ZW1lbnQgaXMgZXhhY3RseSB0aGUgc2FtZS5cbiAgICogLSBDb21iaW5lIEFjdGlvbnMgaWYgdGhlIHJlc3Qgb2YgdGhlIHN0YXRlbWVudCBpcyBleGFjdGx5IHRoZSBzYW1lLlxuICAgKiAtIFdlIHdpbGwgbmV2ZXIgY29tYmluZSBOb3RQcmluY2lwYWxzLCBOb3RSZXNvdXJjZXMgb3IgTm90QWN0aW9ucywgYmVjYXVzZSBkb2luZ1xuICAgKiAgIHNvIHdvdWxkIGNoYW5nZSB0aGUgbWVhbmluZyBvZiB0aGUgcG9saWN5IGRvY3VtZW50LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGZhbHNlLCB1bmxlc3MgdGhlIGZlYXR1cmUgZmxhZyBgQGF3cy1jZGsvYXdzLWlhbTptaW5pbWl6ZVBvbGljaWVzYCBpcyBzZXRcbiAgICovXG4gIHJlYWRvbmx5IG1pbmltaXplPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBBIFBvbGljeURvY3VtZW50IGlzIGEgY29sbGVjdGlvbiBvZiBzdGF0ZW1lbnRzXG4gKi9cbmV4cG9ydCBjbGFzcyBQb2xpY3lEb2N1bWVudCBpbXBsZW1lbnRzIGNkay5JUmVzb2x2YWJsZSB7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgUG9saWN5RG9jdW1lbnQgYmFzZWQgb24gdGhlIG9iamVjdCBwcm92aWRlZC5cbiAgICogVGhpcyB3aWxsIGFjY2VwdCBhbiBvYmplY3QgY3JlYXRlZCBmcm9tIHRoZSBgLnRvSlNPTigpYCBjYWxsXG4gICAqIEBwYXJhbSBvYmogdGhlIFBvbGljeURvY3VtZW50IGluIG9iamVjdCBmb3JtLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmcm9tSnNvbihvYmo6IGFueSk6IFBvbGljeURvY3VtZW50IHtcbiAgICBjb25zdCBuZXdQb2xpY3lEb2N1bWVudCA9IG5ldyBQb2xpY3lEb2N1bWVudCgpO1xuICAgIGNvbnN0IHN0YXRlbWVudCA9IG9iai5TdGF0ZW1lbnQgPz8gW107XG4gICAgaWYgKHN0YXRlbWVudCAmJiAhQXJyYXkuaXNBcnJheShzdGF0ZW1lbnQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1N0YXRlbWVudCBtdXN0IGJlIGFuIGFycmF5Jyk7XG4gICAgfVxuICAgIG5ld1BvbGljeURvY3VtZW50LmFkZFN0YXRlbWVudHMoLi4ub2JqLlN0YXRlbWVudC5tYXAoKHM6IGFueSkgPT4gUG9saWN5U3RhdGVtZW50LmZyb21Kc29uKHMpKSk7XG4gICAgcmV0dXJuIG5ld1BvbGljeURvY3VtZW50O1xuICB9XG5cbiAgcHVibGljIHJlYWRvbmx5IGNyZWF0aW9uU3RhY2s6IHN0cmluZ1tdO1xuICBwcml2YXRlIHJlYWRvbmx5IHN0YXRlbWVudHMgPSBuZXcgQXJyYXk8UG9saWN5U3RhdGVtZW50PigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGF1dG9Bc3NpZ25TaWRzOiBib29sZWFuO1xuICBwcml2YXRlIHJlYWRvbmx5IG1pbmltaXplPzogYm9vbGVhbjtcblxuICBjb25zdHJ1Y3Rvcihwcm9wczogUG9saWN5RG9jdW1lbnRQcm9wcyA9IHt9KSB7XG4gICAgdGhpcy5jcmVhdGlvblN0YWNrID0gY2RrLmNhcHR1cmVTdGFja1RyYWNlKCk7XG4gICAgdGhpcy5hdXRvQXNzaWduU2lkcyA9ICEhcHJvcHMuYXNzaWduU2lkcztcbiAgICB0aGlzLm1pbmltaXplID0gcHJvcHMubWluaW1pemU7XG5cbiAgICB0aGlzLmFkZFN0YXRlbWVudHMoLi4ucHJvcHMuc3RhdGVtZW50cyB8fCBbXSk7XG4gIH1cblxuICBwdWJsaWMgcmVzb2x2ZShjb250ZXh0OiBjZGsuSVJlc29sdmVDb250ZXh0KTogYW55IHtcbiAgICB0aGlzLl9tYXliZU1lcmdlU3RhdGVtZW50cyhjb250ZXh0LnNjb3BlKTtcblxuICAgIC8vIEluIHRoZSBwcmV2aW91cyBpbXBsZW1lbnRhdGlvbiBvZiAnbWVyZ2UnLCBzb3J0aW5nIG9mIGFjdGlvbnMvcmVzb3VyY2VzIG9uXG4gICAgLy8gYSBzdGF0ZW1lbnQgYWx3YXlzIGhhcHBlbmVkLCBldmVuICBvbiBzaW5ndWxhciBzdGF0ZW1lbnRzLiBJbiB0aGUgbmV3XG4gICAgLy8gaW1wbGVtZW50YXRpb24gb2YgJ21lcmdlJywgc29ydGluZyBvbmx5IGhhcHBlbnMgd2hlbiBhY3R1YWxseSBjb21iaW5pbmcgMlxuICAgIC8vIHN0YXRlbWVudHMuIFRoaXMgYWZmZWN0cyBhbGwgdGVzdCBzbmFwc2hvdHMsIHNvIHdlIG5lZWQgdG8gcHV0IGluIG1lY2hhbmlzbXNcbiAgICAvLyB0byBhdm9pZCBoYXZpbmcgdG8gdXBkYXRlIGFsbCBzbmFwc2hvdHMuXG4gICAgLy9cbiAgICAvLyBUbyBkbyBzb3J0aW5nIGluIGEgd2F5IGNvbXBhdGlibGUgd2l0aCB0aGUgcHJldmlvdXMgaW1wbGVtZW50YXRpb24gb2YgbWVyZ2luZyxcbiAgICAvLyAoc28gd2UgZG9uJ3QgaGF2ZSB0byB1cGRhdGUgc25hcHNob3RzKSBkbyBpdCBhZnRlciByZW5kZXJpbmcsIGJ1dCBvbmx5IHdoZW5cbiAgICAvLyBtZXJnaW5nIGlzIGVuYWJsZWQuXG4gICAgY29uc3Qgc29ydCA9IHRoaXMuc2hvdWxkTWVyZ2UoY29udGV4dC5zY29wZSk7XG4gICAgY29udGV4dC5yZWdpc3RlclBvc3RQcm9jZXNzb3IobmV3IFBvc3RQcm9jZXNzUG9saWN5RG9jdW1lbnQodGhpcy5hdXRvQXNzaWduU2lkcywgc29ydCkpO1xuICAgIHJldHVybiB0aGlzLnJlbmRlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHBvbGljeSBkb2N1bWVudCBjb250YWlucyBhbnkgc3RhdGVtZW50cy5cbiAgICovXG4gIHB1YmxpYyBnZXQgaXNFbXB0eSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZW1lbnRzLmxlbmd0aCA9PT0gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIHN0YXRlbWVudHMgYWxyZWFkeSBhZGRlZCB0byB0aGlzIHBvbGljeS5cbiAgICogQ2FuIGJlIHVzZWQsIGZvciBleGFtcGxlLCB0byBnZW5lcmF0ZSB1bmlxdWUgXCJzaWRcInMgd2l0aGluIHRoZSBwb2xpY3kuXG4gICAqL1xuICBwdWJsaWMgZ2V0IHN0YXRlbWVudENvdW50KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGVtZW50cy5sZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHN0YXRlbWVudCB0byB0aGUgcG9saWN5IGRvY3VtZW50LlxuICAgKlxuICAgKiBAcGFyYW0gc3RhdGVtZW50IHRoZSBzdGF0ZW1lbnQgdG8gYWRkLlxuICAgKi9cbiAgcHVibGljIGFkZFN0YXRlbWVudHMoLi4uc3RhdGVtZW50OiBQb2xpY3lTdGF0ZW1lbnRbXSkge1xuICAgIHRoaXMuc3RhdGVtZW50cy5wdXNoKC4uLnN0YXRlbWVudCk7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RlIHRoZSBwb2xpY3kgZG9jdW1lbnQgYXMgYSBzdHJpbmdcbiAgICovXG4gIHB1YmxpYyB0b1N0cmluZygpIHtcbiAgICByZXR1cm4gY2RrLlRva2VuLmFzU3RyaW5nKHRoaXMsIHtcbiAgICAgIGRpc3BsYXlIaW50OiAnUG9saWN5RG9jdW1lbnQnLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEpTT04taWZ5IHRoZSBkb2N1bWVudFxuICAgKlxuICAgKiBVc2VkIHdoZW4gSlNPTi5zdHJpbmdpZnkoKSBpcyBjYWxsZWRcbiAgICovXG4gIHB1YmxpYyB0b0pTT04oKSB7XG4gICAgcmV0dXJuIHRoaXMucmVuZGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgdGhhdCBhbGwgcG9saWN5IHN0YXRlbWVudHMgaW4gdGhlIHBvbGljeSBkb2N1bWVudCBzYXRpc2ZpZXMgdGhlXG4gICAqIHJlcXVpcmVtZW50cyBmb3IgYW55IHBvbGljeS5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vSUFNL2xhdGVzdC9Vc2VyR3VpZGUvYWNjZXNzX3BvbGljaWVzLmh0bWwjYWNjZXNzX3BvbGljaWVzLWpzb25cbiAgICpcbiAgICogQHJldHVybnMgQW4gYXJyYXkgb2YgdmFsaWRhdGlvbiBlcnJvciBtZXNzYWdlcywgb3IgYW4gZW1wdHkgYXJyYXkgaWYgdGhlIGRvY3VtZW50IGlzIHZhbGlkLlxuICAgKi9cbiAgcHVibGljIHZhbGlkYXRlRm9yQW55UG9saWN5KCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBlcnJvcnMgPSBuZXcgQXJyYXk8c3RyaW5nPigpO1xuICAgIGZvciAoY29uc3Qgc3RhdGVtZW50IG9mIHRoaXMuc3RhdGVtZW50cykge1xuICAgICAgZXJyb3JzLnB1c2goLi4uc3RhdGVtZW50LnZhbGlkYXRlRm9yQW55UG9saWN5KCkpO1xuICAgIH1cbiAgICByZXR1cm4gZXJyb3JzO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoYXQgYWxsIHBvbGljeSBzdGF0ZW1lbnRzIGluIHRoZSBwb2xpY3kgZG9jdW1lbnQgc2F0aXNmaWVzIHRoZVxuICAgKiByZXF1aXJlbWVudHMgZm9yIGEgcmVzb3VyY2UtYmFzZWQgcG9saWN5LlxuICAgKlxuICAgKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9JQU0vbGF0ZXN0L1VzZXJHdWlkZS9hY2Nlc3NfcG9saWNpZXMuaHRtbCNhY2Nlc3NfcG9saWNpZXMtanNvblxuICAgKlxuICAgKiBAcmV0dXJucyBBbiBhcnJheSBvZiB2YWxpZGF0aW9uIGVycm9yIG1lc3NhZ2VzLCBvciBhbiBlbXB0eSBhcnJheSBpZiB0aGUgZG9jdW1lbnQgaXMgdmFsaWQuXG4gICAqL1xuICBwdWJsaWMgdmFsaWRhdGVGb3JSZXNvdXJjZVBvbGljeSgpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgZXJyb3JzID0gbmV3IEFycmF5PHN0cmluZz4oKTtcbiAgICBmb3IgKGNvbnN0IHN0YXRlbWVudCBvZiB0aGlzLnN0YXRlbWVudHMpIHtcbiAgICAgIGVycm9ycy5wdXNoKC4uLnN0YXRlbWVudC52YWxpZGF0ZUZvclJlc291cmNlUG9saWN5KCkpO1xuICAgIH1cbiAgICByZXR1cm4gZXJyb3JzO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoYXQgYWxsIHBvbGljeSBzdGF0ZW1lbnRzIGluIHRoZSBwb2xpY3kgZG9jdW1lbnQgc2F0aXNmaWVzIHRoZVxuICAgKiByZXF1aXJlbWVudHMgZm9yIGFuIGlkZW50aXR5LWJhc2VkIHBvbGljeS5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vSUFNL2xhdGVzdC9Vc2VyR3VpZGUvYWNjZXNzX3BvbGljaWVzLmh0bWwjYWNjZXNzX3BvbGljaWVzLWpzb25cbiAgICpcbiAgICogQHJldHVybnMgQW4gYXJyYXkgb2YgdmFsaWRhdGlvbiBlcnJvciBtZXNzYWdlcywgb3IgYW4gZW1wdHkgYXJyYXkgaWYgdGhlIGRvY3VtZW50IGlzIHZhbGlkLlxuICAgKi9cbiAgcHVibGljIHZhbGlkYXRlRm9ySWRlbnRpdHlQb2xpY3koKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IGVycm9ycyA9IG5ldyBBcnJheTxzdHJpbmc+KCk7XG4gICAgZm9yIChjb25zdCBzdGF0ZW1lbnQgb2YgdGhpcy5zdGF0ZW1lbnRzKSB7XG4gICAgICBlcnJvcnMucHVzaCguLi5zdGF0ZW1lbnQudmFsaWRhdGVGb3JJZGVudGl0eVBvbGljeSgpKTtcbiAgICB9XG4gICAgcmV0dXJuIGVycm9ycztcbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJmb3JtIHN0YXRlbWVudCBtZXJnaW5nIChpZiBlbmFibGVkIGFuZCBub3QgZG9uZSB5ZXQpXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHVibGljIF9tYXliZU1lcmdlU3RhdGVtZW50cyhzY29wZTogY2RrLklDb25zdHJ1Y3QpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5zaG91bGRNZXJnZShzY29wZSkpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IG1lcmdlU3RhdGVtZW50cyhzY29wZSwgdGhpcy5zdGF0ZW1lbnRzLCBmYWxzZSk7XG4gICAgICB0aGlzLnN0YXRlbWVudHMuc3BsaWNlKDAsIHRoaXMuc3RhdGVtZW50cy5sZW5ndGgsIC4uLnJlc3VsdC5tZXJnZWRTdGF0ZW1lbnRzKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3BsaXQgdGhlIHN0YXRlbWVudHMgb2YgdGhlIFBvbGljeURvY3VtZW50IGludG8gbXVsdGlwbGUgZ3JvdXBzLCBsaW1pdGVkIGJ5IHRoZWlyIHNpemVcbiAgICpcbiAgICogV2UgZG8gYSByb3VuZCBvZiBzaXplLWxpbWl0ZWQgbWVyZ2luZyBmaXJzdCAobWFraW5nIHN1cmUgdG8gbm90IHByb2R1Y2Ugc3RhdGVtZW50cyB0b29cbiAgICogbGFyZ2UgdG8gZml0IGludG8gc3RhbmRhbG9uZSBwb2xpY2llcyksIHNvIHRoYXQgd2UgY2FuIG1vc3QgYWNjdXJhdGVseSBlc3RpbWF0ZSB0b3RhbFxuICAgKiBwb2xpY3kgc2l6ZS4gQW5vdGhlciBmaW5hbCByb3VuZCBvZiBtaW5pbWl6YXRpb24gd2lsbCBiZSBkb25lIGp1c3QgYmVmb3JlIHJlbmRlcmluZyB0b1xuICAgKiBlbmQgdXAgd2l0aCBtaW5pbWFsIHBvbGljaWVzIHRoYXQgbG9vayBuaWNlIHRvIGh1bWFucy5cbiAgICpcbiAgICogUmV0dXJuIGEgbWFwIG9mIHRoZSBmaW5hbCBzZXQgb2YgcG9saWN5IGRvY3VtZW50cywgbWFwcGVkIHRvIHRoZSBPUklHSU5BTCAocHJlLW1lcmdlKVxuICAgKiBQb2xpY3lTdGF0ZW1lbnRzIHRoYXQgZW5kZWQgdXAgaW4gdGhlIGdpdmVuIFBvbGljeURvY3VtZW50LlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHB1YmxpYyBfc3BsaXREb2N1bWVudChzY29wZTogSUNvbnN0cnVjdCwgc2VsZk1heGltdW1TaXplOiBudW1iZXIsIHNwbGl0TWF4aW11bVNpemU6IG51bWJlcik6IE1hcDxQb2xpY3lEb2N1bWVudCwgUG9saWN5U3RhdGVtZW50W10+IHtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICBjb25zdCBuZXdEb2NzOiBQb2xpY3lEb2N1bWVudFtdID0gW107XG5cbiAgICAvLyBNYXBzIGZpbmFsIHN0YXRlbWVudHMgdG8gb3JpZ2luYWwgc3RhdGVtZW50c1xuICAgIGxldCBzdGF0ZW1lbnRzVG9PcmlnaW5hbHMgPSBuZXcgTWFwKHRoaXMuc3RhdGVtZW50cy5tYXAocyA9PiBbcywgW3NdXSkpO1xuICAgIGlmICh0aGlzLnNob3VsZE1lcmdlKHNjb3BlKSkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gbWVyZ2VTdGF0ZW1lbnRzKHNjb3BlLCB0aGlzLnN0YXRlbWVudHMsIHRydWUpO1xuICAgICAgdGhpcy5zdGF0ZW1lbnRzLnNwbGljZSgwLCB0aGlzLnN0YXRlbWVudHMubGVuZ3RoLCAuLi5yZXN1bHQubWVyZ2VkU3RhdGVtZW50cyk7XG4gICAgICBzdGF0ZW1lbnRzVG9PcmlnaW5hbHMgPSByZXN1bHQub3JpZ2luc01hcDtcbiAgICB9XG5cbiAgICBjb25zdCBzaXplT3B0aW9ucyA9IGRlcml2ZUVzdGltYXRlU2l6ZU9wdGlvbnMoc2NvcGUpO1xuXG4gICAgLy8gQ2FjaGUgc3RhdGVtZW50IHNpemVzIHRvIGF2b2lkIHJlY29tcHV0aW5nIHRoZW0gYmFzZWQgb24gdGhlIGZpZWxkc1xuICAgIGNvbnN0IHN0YXRlbWVudFNpemVzID0gbmV3IE1hcDxQb2xpY3lTdGF0ZW1lbnQsIG51bWJlcj4odGhpcy5zdGF0ZW1lbnRzLm1hcChzID0+IFtzLCBzLl9lc3RpbWF0ZVNpemUoc2l6ZU9wdGlvbnMpXSkpO1xuXG4gICAgLy8gS2VlcCBzb21lIHNpemUgY291bnRlcnMgc28gd2UgY2FuIGF2b2lkIHJlY29tcHV0aW5nIHRoZW0gYmFzZWQgb24gdGhlIHN0YXRlbWVudHMgaW4gZWFjaFxuICAgIGxldCBzZWxmU2l6ZSA9IDA7XG4gICAgY29uc3QgcG9sU2l6ZXMgPSBuZXcgTWFwPFBvbGljeURvY3VtZW50LCBudW1iZXI+KCk7XG4gICAgLy8gR2V0dGVyIHdpdGggYSBkZWZhdWx0IHRvIHNhdmUgc29tZSBzeW50YWN0aWMgbm9pc2VcbiAgICBjb25zdCBwb2xTaXplID0gKHg6IFBvbGljeURvY3VtZW50KSA9PiBwb2xTaXplcy5nZXQoeCkgPz8gMDtcblxuICAgIGxldCBpID0gMDtcbiAgICB3aGlsZSAoaSA8IHRoaXMuc3RhdGVtZW50cy5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IHN0YXRlbWVudCA9IHRoaXMuc3RhdGVtZW50c1tpXTtcblxuICAgICAgY29uc3Qgc3RhdGVtZW50U2l6ZSA9IHN0YXRlbWVudFNpemVzLmdldChzdGF0ZW1lbnQpID8/IDA7XG4gICAgICBpZiAoc2VsZlNpemUgKyBzdGF0ZW1lbnRTaXplIDwgc2VsZk1heGltdW1TaXplKSB7XG4gICAgICAgIC8vIEZpdHMgaW4gc2VsZlxuICAgICAgICBzZWxmU2l6ZSArPSBzdGF0ZW1lbnRTaXplO1xuICAgICAgICBpKys7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBTcGxpdCBvZmYgdG8gbmV3IFBvbGljeURvY3VtZW50LiBGaW5kIHRoZSBQb2xpY3lEb2N1bWVudCB3ZSBjYW4gYWRkIHRoaXMgdG8sXG4gICAgICAvLyBvciBhZGQgYSBmcmVzaCBvbmUuXG4gICAgICBjb25zdCBhZGRUb0RvYyA9IGZpbmREb2NXaXRoU3BhY2Uoc3RhdGVtZW50U2l6ZSk7XG4gICAgICBhZGRUb0RvYy5hZGRTdGF0ZW1lbnRzKHN0YXRlbWVudCk7XG4gICAgICBwb2xTaXplcy5zZXQoYWRkVG9Eb2MsIHBvbFNpemUoYWRkVG9Eb2MpICsgc3RhdGVtZW50U2l6ZSk7XG4gICAgICB0aGlzLnN0YXRlbWVudHMuc3BsaWNlKGksIDEpO1xuICAgIH1cblxuICAgIC8vIFJldHVybiB0aGUgc2V0IG9mIGFsbCBwb2xpY3kgZG9jdW1lbnQgYW5kIG9yaWdpbmFsIHN0YXRlbWVudHNcbiAgICBjb25zdCByZXQgPSBuZXcgTWFwPFBvbGljeURvY3VtZW50LCBQb2xpY3lTdGF0ZW1lbnRbXT4oKTtcbiAgICByZXQuc2V0KHRoaXMsIHRoaXMuc3RhdGVtZW50cy5mbGF0TWFwKHMgPT4gc3RhdGVtZW50c1RvT3JpZ2luYWxzLmdldChzKSA/PyBbc10pKTtcbiAgICBmb3IgKGNvbnN0IG5ld0RvYyBvZiBuZXdEb2NzKSB7XG4gICAgICByZXQuc2V0KG5ld0RvYywgbmV3RG9jLnN0YXRlbWVudHMuZmxhdE1hcChzID0+IHN0YXRlbWVudHNUb09yaWdpbmFscy5nZXQocykgPz8gW3NdKSk7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG5cbiAgICBmdW5jdGlvbiBmaW5kRG9jV2l0aFNwYWNlKHNpemU6IG51bWJlcikge1xuICAgICAgbGV0IGogPSAwO1xuICAgICAgd2hpbGUgKGogPCBuZXdEb2NzLmxlbmd0aCAmJiBwb2xTaXplKG5ld0RvY3Nbal0pICsgc2l6ZSA+IHNwbGl0TWF4aW11bVNpemUpIHtcbiAgICAgICAgaisrO1xuICAgICAgfVxuICAgICAgaWYgKGogPCBuZXdEb2NzLmxlbmd0aCkge1xuICAgICAgICByZXR1cm4gbmV3RG9jc1tqXTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbmV3RG9jID0gbmV3IFBvbGljeURvY3VtZW50KHtcbiAgICAgICAgYXNzaWduU2lkczogc2VsZi5hdXRvQXNzaWduU2lkcyxcbiAgICAgICAgbWluaW1pemU6IHNlbGYubWluaW1pemUsXG4gICAgICB9KTtcbiAgICAgIG5ld0RvY3MucHVzaChuZXdEb2MpO1xuICAgICAgcmV0dXJuIG5ld0RvYztcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlbmRlcigpOiBhbnkge1xuICAgIGlmICh0aGlzLmlzRW1wdHkpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgY29uc3QgZG9jID0ge1xuICAgICAgU3RhdGVtZW50OiB0aGlzLnN0YXRlbWVudHMubWFwKHMgPT4gcy50b1N0YXRlbWVudEpzb24oKSksXG4gICAgICBWZXJzaW9uOiAnMjAxMi0xMC0xNycsXG4gICAgfTtcblxuICAgIHJldHVybiBkb2M7XG4gIH1cblxuICBwcml2YXRlIHNob3VsZE1lcmdlKHNjb3BlOiBJQ29uc3RydWN0KSB7XG4gICAgcmV0dXJuIHRoaXMubWluaW1pemUgPz8gY2RrLkZlYXR1cmVGbGFncy5vZihzY29wZSkuaXNFbmFibGVkKGN4YXBpLklBTV9NSU5JTUlaRV9QT0xJQ0lFUykgPz8gZmFsc2U7XG4gIH1cbn1cbiJdfQ==