UNPKG

@aws-cdk/aws-ec2

Version:

The CDK Construct Library for AWS::EC2

233 lines 26.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CidrBlock = exports.NetworkBuilder = exports.NetworkUtils = exports.InvalidCidrRangeError = void 0; /** * InvalidCidrRangeError is thrown when attempting to perform operations on a CIDR * range that is either not valid, or outside of the VPC size limits. */ class InvalidCidrRangeError extends Error { constructor(cidr) { super(cidr + ' is not a valid VPC CIDR range (must be between /16 and /28)'); // The following line is required for type checking of custom errors, and must be called right after super() // https://stackoverflow.com/questions/31626231/custom-error-class-in-typescript Object.setPrototypeOf(this, InvalidCidrRangeError.prototype); } } exports.InvalidCidrRangeError = InvalidCidrRangeError; /** * NetworkUtils contains helpers to work with network constructs (subnets/ranges) */ class NetworkUtils { /** * Validates an IPv4 string * * returns true of the string contains 4 numbers between 0-255 delimited by * a `.` character */ static validIp(ipAddress) { const octets = ipAddress.split('.'); if (octets.length !== 4) { return false; } return octets.map((octet) => parseInt(octet, 10)). filter((octet) => octet >= 0 && octet <= 255).length === 4; } /** * Converts a string IPv4 to a number * * takes an IP Address (e.g. 174.66.173.168) and converts to a number * (e.g 2923605416); currently only supports IPv4 * * Uses the formula: * (first octet * 256³) + (second octet * 256²) + (third octet * 256) + * (fourth octet) * * @param {string} the IP address (e.g. 174.66.173.168) * @returns {number} the integer value of the IP address (e.g 2923605416) */ static ipToNum(ipAddress) { if (!this.validIp(ipAddress)) { throw new Error(`${ipAddress} is not valid`); } return ipAddress .split('.') .reduce((p, c, i) => p + parseInt(c, 10) * 256 ** (3 - i), 0); } /** * Takes number and converts it to IPv4 address string * * Takes a number (e.g 2923605416) and converts it to an IPv4 address string * currently only supports IPv4 * * @param {number} the integer value of the IP address (e.g 2923605416) * @returns {string} the IPv4 address (e.g. 174.66.173.168) */ static numToIp(ipNum) { // this all because bitwise math is signed let remaining = ipNum; const address = new Array(); for (let i = 0; i < 4; i++) { if (remaining !== 0) { address.push(Math.floor(remaining / 256 ** (3 - i))); remaining = remaining % 256 ** (3 - i); } else { address.push(0); } } const ipAddress = address.join('.'); if (!this.validIp(ipAddress)) { throw new Error(`${ipAddress} is not a valid IP Address`); } return ipAddress; } } exports.NetworkUtils = NetworkUtils; /** * Creates a network based on a CIDR Block to build contained subnets */ class NetworkBuilder { /** * Create a network using the provided CIDR block * * No subnets are allocated in the constructor, the maxIpConsumed is set one * less than the first IP in the network * */ constructor(cidr) { /** * The list of CIDR blocks for subnets within this network */ this.subnetCidrs = []; this.networkCidr = new CidrBlock(cidr); this.subnetCidrs = []; this.nextAvailableIp = this.networkCidr.minAddress(); } /** * Add a subnet to the network and update the maxIpConsumed */ addSubnet(mask) { return this.addSubnets(mask, 1)[0]; } /** * Add {count} number of subnets to the network and update the maxIpConsumed */ addSubnets(mask, count = 1) { if (mask < 16 || mask > 28) { throw new InvalidCidrRangeError(`x.x.x.x/${mask}`); } const maxIp = this.nextAvailableIp + (CidrBlock.calculateNetsize(mask) * count); if (this.networkCidr.maxAddress() < maxIp - 1) { throw new Error(`${count} of /${mask} exceeds remaining space of ${this.networkCidr.cidr}`); } const subnets = []; for (let i = 0; i < count; i++) { const subnet = new CidrBlock(this.nextAvailableIp, mask); this.nextAvailableIp = subnet.nextBlock().minAddress(); this.subnetCidrs.push(subnet); subnets.push(subnet); } return subnets.map((subnet) => (subnet.cidr)); } /** * return the CIDR notation strings for all subnets in the network */ get cidrStrings() { return this.subnetCidrs.map((subnet) => (subnet.cidr)); } /** * Calculates the largest subnet to create of the given count from the * remaining IP space */ maskForRemainingSubnets(subnetCount) { const remaining = this.networkCidr.maxAddress() - this.nextAvailableIp + 1; const ipsPerSubnet = Math.floor(remaining / subnetCount); return 32 - Math.floor(Math.log2(ipsPerSubnet)); } } exports.NetworkBuilder = NetworkBuilder; /** * A block of IP address space with a given bit prefix */ class CidrBlock { constructor(ipAddressOrCidr, mask) { if (typeof ipAddressOrCidr === 'string') { this.mask = parseInt(ipAddressOrCidr.split('/')[1], 10); this.networkAddress = NetworkUtils.ipToNum(ipAddressOrCidr.split('/')[0]) + CidrBlock.calculateNetsize(this.mask) - 1; } else { if (typeof mask === 'number') { this.mask = mask; } else { // this should be impossible this.mask = 16; } this.networkAddress = ipAddressOrCidr + CidrBlock.calculateNetsize(this.mask) - 1; this.networkSize = 2 ** (32 - this.mask); } this.networkSize = 2 ** (32 - this.mask); this.cidr = `${this.minIp()}/${this.mask}`; } /** * Calculates the netmask for a given CIDR mask * * For example: * CidrBlock.calculateNetmask(24) returns '255.255.255.0' */ static calculateNetmask(mask) { return NetworkUtils.numToIp(2 ** 32 - 2 ** (32 - mask)); } /** * Calculates the number IP addresses in a CIDR Mask * * For example: * CidrBlock.calculateNetsize(24) returns 256 */ static calculateNetsize(mask) { return 2 ** (32 - mask); } /* * The maximum IP in the CIDR Block e.g. '10.0.8.255' */ maxIp() { // min + (2^(32-mask)) - 1 [zero needs to count] return NetworkUtils.numToIp(this.maxAddress()); } /* * The minimum IP in the CIDR Block e.g. '10.0.0.0' */ minIp() { return NetworkUtils.numToIp(this.minAddress()); } /* * Returns the number representation for the minimum IPv4 address */ minAddress() { const div = this.networkAddress % this.networkSize; return this.networkAddress - div; } /* * Returns the number representation for the maximum IPv4 address */ maxAddress() { // min + (2^(32-mask)) - 1 [zero needs to count] return this.minAddress() + this.networkSize - 1; } /* * Returns the next CIDR Block of the same mask size */ nextBlock() { return new CidrBlock(this.maxAddress() + 1, this.mask); } /* * Returns true if this CidrBlock fully contains the provided CidrBlock */ containsCidr(other) { return (this.maxAddress() >= other.maxAddress()) && (this.minAddress() <= other.minAddress()); } } exports.CidrBlock = CidrBlock; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV0d29yay11dGlsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibmV0d29yay11dGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBOzs7R0FHRztBQUNILE1BQWEscUJBQXNCLFNBQVEsS0FBSztJQUM5QyxZQUFZLElBQVk7UUFDdEIsS0FBSyxDQUFDLElBQUksR0FBRyw4REFBOEQsQ0FBQyxDQUFDO1FBQzdFLDRHQUE0RztRQUM1RyxnRkFBZ0Y7UUFDaEYsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUscUJBQXFCLENBQUMsU0FBUyxDQUFDLENBQUM7S0FDOUQ7Q0FDRjtBQVBELHNEQU9DO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLFlBQVk7SUFFdkI7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQWlCO1FBQ3JDLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDcEMsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUN2QixPQUFPLEtBQUssQ0FBQztTQUNkO1FBQ0QsT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBYSxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELE1BQU0sQ0FBQyxDQUFDLEtBQWEsRUFBRSxFQUFFLENBQUMsS0FBSyxJQUFJLENBQUMsSUFBSSxLQUFLLElBQUksR0FBRyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQztLQUN0RTtJQUVEOzs7Ozs7Ozs7Ozs7T0FZRztJQUNJLE1BQU0sQ0FBQyxPQUFPLENBQUMsU0FBaUI7UUFDckMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUU7WUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLFNBQVMsZUFBZSxDQUFDLENBQUM7U0FDOUM7UUFFRCxPQUFPLFNBQVM7YUFDYixLQUFL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OztPQUVHO0lBQ0ksS0FBSztRQUNWLGdEQUFnRDtRQUNoRCxPQUFPLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7S0FDaEQ7SUFFRDs7T0FFRztJQUNJLEtBQUs7UUFDVixPQUFPLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7S0FDaEQ7SUFFRDs7T0FFRztJQUNJLFVBQVU7UUFDZixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUM7UUFDbkQsT0FBTyxJQUFJLENBQUMsY0FBYyxHQUFHLEdBQUcsQ0FBQztLQUNsQztJQUVEOztPQUVHO0lBQ0ksVUFBVTtRQUNmLGdEQUFnRDtRQUNoRCxPQUFPLElBQUksQ0FBQyxVQUFVLEVBQUUsR0FBRyxJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQztLQUNqRDtJQUVEOztPQUVHO0lBQ0ksU0FBUztRQUNkLE9BQU8sSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7S0FDeEQ7SUFFRDs7T0FFRztJQUNJLFlBQVksQ0FBQyxLQUFnQjtRQUNsQyxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUM5QyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztLQUM3QztDQUNGO0FBeEhELDhCQXdIQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogSW52YWxpZENpZHJSYW5nZUVycm9yIGlzIHRocm93biB3aGVuIGF0dGVtcHRpbmcgdG8gcGVyZm9ybSBvcGVyYXRpb25zIG9uIGEgQ0lEUlxuICogcmFuZ2UgdGhhdCBpcyBlaXRoZXIgbm90IHZhbGlkLCBvciBvdXRzaWRlIG9mIHRoZSBWUEMgc2l6ZSBsaW1pdHMuXG4gKi9cbmV4cG9ydCBjbGFzcyBJbnZhbGlkQ2lkclJhbmdlRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKGNpZHI6IHN0cmluZykge1xuICAgIHN1cGVyKGNpZHIgKyAnIGlzIG5vdCBhIHZhbGlkIFZQQyBDSURSIHJhbmdlIChtdXN0IGJlIGJldHdlZW4gLzE2IGFuZCAvMjgpJyk7XG4gICAgLy8gVGhlIGZvbGxvd2luZyBsaW5lIGlzIHJlcXVpcmVkIGZvciB0eXBlIGNoZWNraW5nIG9mIGN1c3RvbSBlcnJvcnMsIGFuZCBtdXN0IGJlIGNhbGxlZCByaWdodCBhZnRlciBzdXBlcigpXG4gICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzE2MjYyMzEvY3VzdG9tLWVycm9yLWNsYXNzLWluLXR5cGVzY3JpcHRcbiAgICBPYmplY3Quc2V0UHJvdG90eXBlT2YodGhpcywgSW52YWxpZENpZHJSYW5nZUVycm9yLnByb3RvdHlwZSk7XG4gIH1cbn1cblxuLyoqXG4gKiBOZXR3b3JrVXRpbHMgY29udGFpbnMgaGVscGVycyB0byB3b3JrIHdpdGggbmV0d29yayBjb25zdHJ1Y3RzIChzdWJuZXRzL3JhbmdlcylcbiAqL1xuZXhwb3J0IGNsYXNzIE5ldHdvcmtVdGlscyB7XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyBhbiBJUHY0IHN0cmluZ1xuICAgKlxuICAgKiByZXR1cm5zIHRydWUgb2YgdGhlIHN0cmluZyBjb250YWlucyA0IG51bWJlcnMgYmV0d2VlbiAwLTI1NSBkZWxpbWl0ZWQgYnlcbiAgICogYSBgLmAgY2hhcmFjdGVyXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHZhbGlkSXAoaXBBZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBvY3RldHMgPSBpcEFkZHJlc3Muc3BsaXQoJy4nKTtcbiAgICBpZiAob2N0ZXRzLmxlbmd0aCAhPT0gNCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gb2N0ZXRzLm1hcCgob2N0ZXQ6IHN0cmluZykgPT4gcGFyc2VJbnQob2N0ZXQsIDEwKSkuXG4gICAgICBmaWx0ZXIoKG9jdGV0OiBudW1iZXIpID0+IG9jdGV0ID49IDAgJiYgb2N0ZXQgPD0gMjU1KS5sZW5ndGggPT09IDQ7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSBzdHJpbmcgSVB2NCB0byBhIG51bWJlclxuICAgKlxuICAgKiB0YWtlcyBhbiBJUCBBZGRyZXNzIChlLmcuIDE3NC42Ni4xNzMuMTY4KSBhbmQgY29udmVydHMgdG8gYSBudW1iZXJcbiAgICogKGUuZyAyOTIzNjA1NDE2KTsgY3VycmVudGx5IG9ubHkgc3VwcG9ydHMgSVB2NFxuICAgKlxuICAgKiBVc2VzIHRoZSBmb3JtdWxhOlxuICAgKiAoZmlyc3Qgb2N0ZXQgKiAyNTbCsykgKyAoc2Vjb25kIG9jdGV0ICogMjU2wrIpICsgKHRoaXJkIG9jdGV0ICogMjU2KSArXG4gICAqIChmb3VydGggb2N0ZXQpXG4gICAqXG4gICAqIEBwYXJhbSAge3N0cmluZ30gdGhlIElQIGFkZHJlc3MgKGUuZy4gMTc0LjY2LjE3My4xNjgpXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IHRoZSBpbnRlZ2VyIHZhbHVlIG9mIHRoZSBJUCBhZGRyZXNzIChlLmcgMjkyMzYwNTQxNilcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgaXBUb051bShpcEFkZHJlc3M6IHN0cmluZyk6IG51bWJlciB7XG4gICAgaWYgKCF0aGlzLnZhbGlkSXAoaXBBZGRyZXNzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGAke2lwQWRkcmVzc30gaXMgbm90IHZhbGlkYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGlwQWRkcmVzc1xuICAgICAgLnNwbGl0KCcuJylcbiAgICAgIC5yZWR1Y2UoXG4gICAgICAgIChwOiBudW1iZXIsIGM6IHN0cmluZywgaTogbnVtYmVyKSA9PiBwICsgcGFyc2VJbnQoYywgMTApICogMjU2ICoqICgzIC0gaSksXG4gICAgICAgIDAsXG4gICAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIFRha2VzIG51bWJlciBhbmQgY29udmVydHMgaXQgdG8gSVB2NCBhZGRyZXNzIHN0cmluZ1xuICAgKlxuICAgKiBUYWtlcyBhIG51bWJlciAoZS5nIDI5MjM2MDU0MTYpIGFuZCBjb252ZXJ0cyBpdCB0byBhbiBJUHY0IGFkZHJlc3Mgc3RyaW5nXG4gICAqIGN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIElQdjRcbiAgICpcbiAgICogQHBhcmFtICB7bnVtYmVyfSB0aGUgaW50ZWdlciB2YWx1ZSBvZiB0aGUgSVAgYWRkcmVzcyAoZS5nIDI5MjM2MDU0MTYpXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IHRoZSBJUHY0IGFkZHJlc3MgKGUuZy4gMTc0LjY2LjE3My4xNjgpXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIG51bVRvSXAoaXBOdW06IG51bWJlcik6IHN0cmluZyB7XG4gICAgLy8gdGhpcyBhbGwgYmVjYXVzZSBiaXR3aXNlIG1hdGggaXMgc2lnbmVkXG4gICAgbGV0IHJlbWFpbmluZyA9IGlwTnVtO1xuICAgIGNvbnN0IGFkZHJlc3MgPSBuZXcgQXJyYXk8bnVtYmVyPigpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgNDsgaSsrKSB7XG4gICAgICBpZiAocmVtYWluaW5nICE9PSAwKSB7XG4gICAgICAgIGFkZHJlc3MucHVzaChNYXRoLmZsb29yKHJlbWFpbmluZyAvIDI1NiAqKiAoMyAtIGkpKSk7XG4gICAgICAgIHJlbWFpbmluZyA9IHJlbWFpbmluZyAlIDI1NiAqKiAoMyAtIGkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYWRkcmVzcy5wdXNoKDApO1xuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBpcEFkZHJlc3M6IHN0cmluZyA9IGFkZHJlc3Muam9pbignLicpO1xuICAgIGlmICggIXRoaXMudmFsaWRJcChpcEFkZHJlc3MpICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGAke2lwQWRkcmVzc30gaXMgbm90IGEgdmFsaWQgSVAgQWRkcmVzc2ApO1xuICAgIH1cbiAgICByZXR1cm4gaXBBZGRyZXNzO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldHdvcmsgYmFzZWQgb24gYSBDSURSIEJsb2NrIHRvIGJ1aWxkIGNvbnRhaW5lZCBzdWJuZXRzXG4gKi9cbmV4cG9ydCBjbGFzcyBOZXR3b3JrQnVpbGRlciB7XG5cbiAgLyoqXG4gICAqIFRoZSBDSURSIHJhbmdlIHVzZWQgd2hlbiBjcmVhdGluZyB0aGUgbmV0d29ya1xuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG5ldHdvcmtDaWRyOiBDaWRyQmxvY2s7XG5cbiAgLyoqXG4gICAqIFRoZSBsaXN0IG9mIENJRFIgYmxvY2tzIGZvciBzdWJuZXRzIHdpdGhpbiB0aGlzIG5ldHdvcmtcbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgc3VibmV0Q2lkcnM6IENpZHJCbG9ja1tdID0gW107XG5cbiAgLyoqXG4gICAqIFRoZSBuZXh0IGF2YWlsYWJsZSBJUCBhZGRyZXNzIGFzIGEgbnVtYmVyXG4gICAqL1xuICBwcml2YXRlIG5leHRBdmFpbGFibGVJcDogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBuZXR3b3JrIHVzaW5nIHRoZSBwcm92aWRlZCBDSURSIGJsb2NrXG4gICAqXG4gICAqIE5vIHN1Ym5ldHMgYXJlIGFsbG9jYXRlZCBpbiB0aGUgY29uc3RydWN0b3IsIHRoZSBtYXhJcENvbnN1bWVkIGlzIHNldCBvbmVcbiAgICogbGVzcyB0aGFuIHRoZSBmaXJzdCBJUCBpbiB0aGUgbmV0d29ya1xuICAgKlxuICAgKi9cbiAgY29uc3RydWN0b3IoY2lkcjogc3RyaW5nKSB7XG4gICAgdGhpcy5uZXR3b3JrQ2lkciA9IG5ldyBDaWRyQmxvY2soY2lkcik7XG4gICAgdGhpcy5zdWJuZXRDaWRycyA9IFtdO1xuICAgIHRoaXMubmV4dEF2YWlsYWJsZUlwID0gdGhpcy5uZXR3b3JrQ2lkci5taW5BZGRyZXNzKCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgc3VibmV0IHRvIHRoZSBuZXR3b3JrIGFuZCB1cGRhdGUgdGhlIG1heElwQ29uc3VtZWRcbiAgICovXG4gIHB1YmxpYyBhZGRTdWJuZXQobWFzazogbnVtYmVyKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5hZGRTdWJuZXRzKG1hc2ssIDEpWzBdO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCB7Y291bnR9IG51bWJlciBvZiBzdWJuZXRzIHRvIHRoZSBuZXR3b3JrIGFuZCB1cGRhdGUgdGhlIG1heElwQ29uc3VtZWRcbiAgICovXG4gIHB1YmxpYyBhZGRTdWJuZXRzKG1hc2s6IG51bWJlciwgY291bnQ6IG51bWJlciA9IDEpOiBzdHJpbmdbXSB7XG4gICAgaWYgKG1hc2sgPCAxNiB8fCBtYXNrID4gMjggKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZENpZHJSYW5nZUVycm9yKGB4LngueC54LyR7bWFza31gKTtcbiAgICB9XG4gICAgY29uc3QgbWF4SXAgPSB0aGlzLm5leHRBdmFpbGFibGVJcCArIChDaWRyQmxvY2suY2FsY3VsYXRlTmV0c2l6ZShtYXNrKSAqIGNvdW50KTtcbiAgICBpZiAodGhpcy5uZXR3b3JrQ2lkci5tYXhBZGRyZXNzKCkgPCBtYXhJcCAtIDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtjb3VudH0gb2YgLyR7bWFza30gZXhjZWVkcyByZW1haW5pbmcgc3BhY2Ugb2YgJHt0aGlzLm5ldHdvcmtDaWRyLmNpZHJ9YCk7XG4gICAgfVxuICAgIGNvbnN0IHN1Ym5ldHM6IENpZHJCbG9ja1tdID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjb3VudDsgaSArKykge1xuICAgICAgY29uc3Qgc3VibmV0OiBDaWRyQmxvY2sgPSBuZXcgQ2lkckJsb2NrKHRoaXMubmV4dEF2YWlsYWJsZUlwLCBtYXNrKTtcbiAgICAgIHRoaXMubmV4dEF2YWlsYWJsZUlwID0gc3VibmV0Lm5leHRCbG9jaygpLm1pbkFkZHJlc3MoKTtcbiAgICAgIHRoaXMuc3VibmV0Q2lkcnMucHVzaChzdWJuZXQpO1xuICAgICAgc3VibmV0cy5wdXNoKHN1Ym5ldCk7XG4gICAgfVxuICAgIHJldHVybiBzdWJuZXRzLm1hcCgoc3VibmV0KSA9PiAoc3VibmV0LmNpZHIpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiByZXR1cm4gdGhlIENJRFIgbm90YXRpb24gc3RyaW5ncyBmb3IgYWxsIHN1Ym5ldHMgaW4gdGhlIG5ldHdvcmtcbiAgICovXG4gIHB1YmxpYyBnZXQgY2lkclN0cmluZ3MoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLnN1Ym5ldENpZHJzLm1hcCgoc3VibmV0KSA9PiAoc3VibmV0LmNpZHIpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIHRoZSBsYXJnZXN0IHN1Ym5ldCB0byBjcmVhdGUgb2YgdGhlIGdpdmVuIGNvdW50IGZyb20gdGhlXG4gICAqIHJlbWFpbmluZyBJUCBzcGFjZVxuICAgKi9cbiAgcHVibGljIG1hc2tGb3JSZW1haW5pbmdTdWJuZXRzKHN1Ym5ldENvdW50OiBudW1iZXIpOiBudW1iZXIge1xuICAgIGNvbnN0IHJlbWFpbmluZzogbnVtYmVyID0gdGhpcy5uZXR3b3JrQ2lkci5tYXhBZGRyZXNzKCkgLSB0aGlzLm5leHRBdmFpbGFibGVJcCArIDE7XG4gICAgY29uc3QgaXBzUGVyU3VibmV0OiBudW1iZXIgPSBNYXRoLmZsb29yKHJlbWFpbmluZyAvIHN1Ym5ldENvdW50KTtcbiAgICByZXR1cm4gMzIgLSBNYXRoLmZsb29yKE1hdGgubG9nMihpcHNQZXJTdWJuZXQpKTtcbiAgfVxufVxuXG4vKipcbiAqIEEgYmxvY2sgb2YgSVAgYWRkcmVzcyBzcGFjZSB3aXRoIGEgZ2l2ZW4gYml0IHByZWZpeFxuICovXG5leHBvcnQgY2xhc3MgQ2lkckJsb2NrIHtcblxuICAvKipcbiAgICogQ2FsY3VsYXRlcyB0aGUgbmV0bWFzayBmb3IgYSBnaXZlbiBDSURSIG1hc2tcbiAgICpcbiAgICogRm9yIGV4YW1wbGU6XG4gICAqIENpZHJCbG9jay5jYWxjdWxhdGVOZXRtYXNrKDI0KSByZXR1cm5zICcyNTUuMjU1LjI1NS4wJ1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBjYWxjdWxhdGVOZXRtYXNrKG1hc2s6IG51bWJlcik6IHN0cmluZyB7XG4gICAgcmV0dXJuIE5ldHdvcmtVdGlscy5udW1Ub0lwKDIgKiogMzIgLSAyICoqICgzMiAtIG1hc2spKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIHRoZSBudW1iZXIgSVAgYWRkcmVzc2VzIGluIGEgQ0lEUiBNYXNrXG4gICAqXG4gICAqIEZvciBleGFtcGxlOlxuICAgKiBDaWRyQmxvY2suY2FsY3VsYXRlTmV0c2l6ZSgyNCkgcmV0dXJucyAyNTZcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY2FsY3VsYXRlTmV0c2l6ZShtYXNrOiBudW1iZXIpOiBudW1iZXIge1xuICAgIHJldHVybiAyICoqICgzMiAtIG1hc2spO1xuICB9XG5cbiAgLypcbiAgICogVGhlIENJRFIgQmxvY2sgcmVwcmVzZW50ZWQgYXMgYSBzdHJpbmcgZS5nLiAnMTAuMC4wLjAvMjEnXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY2lkcjogc3RyaW5nO1xuXG4gIC8qXG4gICAqIFRoZSBDSURSIG1hc2sgZS5nLiBmb3IgQ0lEUiAnMTAuMC4wLjAvMjEnIHJldHVybnMgMjFcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBtYXNrOiBudW1iZXI7XG5cbiAgLypcbiAgICogVGhlIHRvdGFsIG51bWJlciBvZiBJUCBhZGRyZXNzZXMgaW4gdGhlIENJRFJcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuZXR3b3JrU2l6ZTogbnVtYmVyO1xuXG4gIC8qXG4gICAqIFRoZSBuZXR3b3JrIGFkZHJlc3MgcHJvdmlkZWQgaW4gQ0lEUiBjcmVhdGlvbiBvZmZzZXQgYnkgdGhlIE5ldHNpemUgLTFcbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgbmV0d29ya0FkZHJlc3M6IG51bWJlcjtcblxuICAvKlxuICAgKiBQYXJzZXMgZWl0aGVyIENJRFIgbm90YXRpb24gU3RyaW5nIG9yIHR3byBudW1iZXJzIHJlcHJlc2VudGluZyB0aGUgSVBcbiAgICogc3BhY2VcbiAgICpcbiAgICogY2lkciBleHBlY3RzIGEgc3RyaW5nICcxMC4wLjAuMC8xNidcbiAgICogaXBBZGRyZXNzIGV4cGVjdHMgYSBudW1iZXJcbiAgICogbWFzayBleHBlY3RzIGEgbnVtYmVyXG4gICAqXG4gICAqIElmIHRoZSBnaXZlbiBgY2lkcmAgb3IgYGlwQWRkcmVzc2AgaXMgbm90IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGJsb2NrLFxuICAgKiB0aGVuIHRoZSBuZXh0IGF2YWlsYWJsZSBibG9jayB3aWxsIGJlIHJldHVybmVkLiBGb3IgZXhhbXBsZSwgaWZcbiAgICogYDEwLjAuMy4xLzI4YCBpcyBnaXZlbiB0aGUgcmV0dXJuZWQgYmxvY2sgd2lsbCByZXByZXNlbnQgYDEwLjAuMy4xNi8yOGAuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihjaWRyOiBzdHJpbmcpXG4gIGNvbnN0cnVjdG9yKGlwQWRkcmVzczogbnVtYmVyLCBtYXNrOiBudW1iZXIpXG4gIGNvbnN0cnVjdG9yKGlwQWRkcmVzc09yQ2lkcjogc3RyaW5nIHwgbnVtYmVyLCBtYXNrPzogbnVtYmVyKSB7XG4gICAgaWYgKHR5cGVvZiBpcEFkZHJlc3NPckNpZHIgPT09ICdzdHJpbmcnKSB7XG4gICAgICB0aGlzLm1hc2sgPSBwYXJzZUludChpcEFkZHJlc3NPckNpZHIuc3BsaXQoJy8nKVsxXSwgMTApO1xuICAgICAgdGhpcy5uZXR3b3JrQWRkcmVzcyA9IE5ldHdvcmtVdGlscy5pcFRvTnVtKGlwQWRkcmVzc09yQ2lkci5zcGxpdCgnLycpWzBdKSArXG4gICAgICAgIENpZHJCbG9jay5jYWxjdWxhdGVOZXRzaXplKHRoaXMubWFzaykgLSAxO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAodHlwZW9mIG1hc2sgPT09ICdudW1iZXInKSB7XG4gICAgICAgIHRoaXMubWFzayA9IG1hc2s7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyB0aGlzIHNob3VsZCBiZSBpbXBvc3NpYmxlXG4gICAgICAgIHRoaXMubWFzayA9IDE2O1xuICAgICAgfVxuICAgICAgdGhpcy5uZXR3b3JrQWRkcmVzcyA9IGlwQWRkcmVzc09yQ2lkciArIENpZHJCbG9jay5jYWxjdWxhdGVOZXRzaXplKHRoaXMubWFzaykgLSAxO1xuICAgICAgdGhpcy5uZXR3b3JrU2l6ZSA9IDIgKiogKDMyIC0gdGhpcy5tYXNrKTtcbiAgICB9XG4gICAgdGhpcy5uZXR3b3JrU2l6ZSA9IDIgKiogKDMyIC0gdGhpcy5tYXNrKTtcbiAgICB0aGlzLmNpZHIgPSBgJHt0aGlzLm1pbklwKCl9LyR7dGhpcy5tYXNrfWA7XG4gIH1cblxuICAvKlxuICAgKiBUaGUgbWF4aW11bSBJUCBpbiB0aGUgQ0lEUiBCbG9jayBlLmcuICcxMC4wLjguMjU1J1xuICAgKi9cbiAgcHVibGljIG1heElwKCk6IHN0cmluZyB7XG4gICAgLy8gbWluICsgKDJeKDMyLW1hc2spKSAtIDEgW3plcm8gbmVlZHMgdG8gY291bnRdXG4gICAgcmV0dXJuIE5ldHdvcmtVdGlscy5udW1Ub0lwKHRoaXMubWF4QWRkcmVzcygpKTtcbiAgfVxuXG4gIC8qXG4gICAqIFRoZSBtaW5pbXVtIElQIGluIHRoZSBDSURSIEJsb2NrIGUuZy4gJzEwLjAuMC4wJ1xuICAgKi9cbiAgcHVibGljIG1pbklwKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIE5ldHdvcmtVdGlscy5udW1Ub0lwKHRoaXMubWluQWRkcmVzcygpKTtcbiAgfVxuXG4gIC8qXG4gICAqIFJldHVybnMgdGhlIG51bWJlciByZXByZXNlbnRhdGlvbiBmb3IgdGhlIG1pbmltdW0gSVB2NCBhZGRyZXNzXG4gICAqL1xuICBwdWJsaWMgbWluQWRkcmVzcygpOiBudW1iZXIge1xuICAgIGNvbnN0IGRpdiA9IHRoaXMubmV0d29ya0FkZHJlc3MgJSB0aGlzLm5ldHdvcmtTaXplO1xuICAgIHJldHVybiB0aGlzLm5ldHdvcmtBZGRyZXNzIC0gZGl2O1xuICB9XG5cbiAgLypcbiAgICogUmV0dXJucyB0aGUgbnVtYmVyIHJlcHJlc2VudGF0aW9uIGZvciB0aGUgbWF4aW11bSBJUHY0IGFkZHJlc3NcbiAgICovXG4gIHB1YmxpYyBtYXhBZGRyZXNzKCk6IG51bWJlciB7XG4gICAgLy8gbWluICsgKDJeKDMyLW1hc2spKSAtIDEgW3plcm8gbmVlZHMgdG8gY291bnRdXG4gICAgcmV0dXJuIHRoaXMubWluQWRkcmVzcygpICsgdGhpcy5uZXR3b3JrU2l6ZSAtIDE7XG4gIH1cblxuICAvKlxuICAgKiBSZXR1cm5zIHRoZSBuZXh0IENJRFIgQmxvY2sgb2YgdGhlIHNhbWUgbWFzayBzaXplXG4gICAqL1xuICBwdWJsaWMgbmV4dEJsb2NrKCk6IENpZHJCbG9jayB7XG4gICAgcmV0dXJuIG5ldyBDaWRyQmxvY2sodGhpcy5tYXhBZGRyZXNzKCkgKyAxLCB0aGlzLm1hc2spO1xuICB9XG5cbiAgLypcbiAgICogUmV0dXJucyB0cnVlIGlmIHRoaXMgQ2lkckJsb2NrIGZ1bGx5IGNvbnRhaW5zIHRoZSBwcm92aWRlZCBDaWRyQmxvY2tcbiAgICovXG4gIHB1YmxpYyBjb250YWluc0NpZHIob3RoZXI6IENpZHJCbG9jayk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAodGhpcy5tYXhBZGRyZXNzKCkgPj0gb3RoZXIubWF4QWRkcmVzcygpKSAmJlxuICAgICAgKHRoaXMubWluQWRkcmVzcygpIDw9IG90aGVyLm1pbkFkZHJlc3MoKSk7XG4gIH1cbn1cbiJdfQ==