lambda-version.js
  1  "use strict";
  2  var _a;
  3  Object.defineProperty(exports, "__esModule", { value: true });
  4  exports.extractQualifierFromArn = exports.Version = void 0;
  5  const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
  6  const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
  7  const core_1 = require("@aws-cdk/core");
  8  const function_1 = require("./function");
  9  const function_base_1 = require("./function-base");
 10  const lambda_generated_1 = require("./lambda.generated");
 11  const util_1 = require("./util");
 12  /**
 13   * A single newly-deployed version of a Lambda function.
 14   *
 15   * This object exists to--at deploy time--query the "then-current" version of
 16   * the Lambda function that it refers to. This Version object can then be
 17   * used in `Alias` to refer to a particular deployment of a Lambda.
 18   *
 19   * This means that for every new update you deploy to your Lambda (using the
 20   * CDK and Aliases), you must always create a new Version object. In
 21   * particular, it must have a different name, so that a new resource is
 22   * created.
 23   *
 24   * If you want to ensure that you're associating the right version with
 25   * the right deployment, specify the `codeSha256` property while
 26   * creating the `Version.
 27   *
 28   * @stability stable
 29   */
 30  class Version extends function_base_1.QualifiedFunctionBase {
 31      /**
 32       * @stability stable
 33       */
 34      constructor(scope, id, props) {
 35          super(scope, id);
 36          /**
 37           * Whether the addPermission() call adds any permissions.
 38           *
 39           * True for new Lambdas, false for version $LATEST and imported Lambdas
 40           * from different accounts.
 41           *
 42           * @stability stable
 43           */
 44          this.canCreatePermissions = true;
 45          jsiiDeprecationWarnings._aws_cdk_aws_lambda_VersionProps(props);
 46          this.lambda = props.lambda;
 47          const version = new lambda_generated_1.CfnVersion(this, 'Resource', {
 48              codeSha256: props.codeSha256,
 49              description: props.description,
 50              functionName: props.lambda.functionName,
 51              provisionedConcurrencyConfig: this.determineProvisionedConcurrency(props),
 52          });
 53          if (props.removalPolicy) {
 54              version.applyRemovalPolicy(props.removalPolicy, {
 55                  default: core_1.RemovalPolicy.DESTROY,
 56              });
 57          }
 58          this.version = version.attrVersion;
 59          this.functionArn = version.ref;
 60          this.functionName = `${this.lambda.functionName}:${this.version}`;
 61          this.qualifier = version.attrVersion;
 62          if (props.onFailure || props.onSuccess || props.maxEventAge || props.retryAttempts !== undefined) {
 63              this.configureAsyncInvoke({
 64                  onFailure: props.onFailure,
 65                  onSuccess: props.onSuccess,
 66                  maxEventAge: props.maxEventAge,
 67                  retryAttempts: props.retryAttempts,
 68              });
 69          }
 70      }
 71      /**
 72       * Construct a Version object from a Version ARN.
 73       *
 74       * @param scope The cdk scope creating this resource.
 75       * @param id The cdk id of this resource.
 76       * @param versionArn The version ARN to create this version from.
 77       * @stability stable
 78       */
 79      static fromVersionArn(scope, id, versionArn) {
 80          const version = extractQualifierFromArn(versionArn);
 81          const lambda = function_1.Function.fromFunctionArn(scope, `${id}Function`, versionArn);
 82          class Import extends function_base_1.QualifiedFunctionBase {
 83              constructor() {
 84                  super(...arguments);
 85                  this.version = version;
 86                  this.lambda = lambda;
 87                  this.functionName = `${lambda.functionName}:${version}`;
 88                  this.functionArn = versionArn;
 89                  this.grantPrincipal = lambda.grantPrincipal;
 90                  this.role = lambda.role;
 91                  this.qualifier = version;
 92                  this.canCreatePermissions = this._isStackAccount();
 93              }
 94              addAlias(name, opts = {}) {
 95                  return util_1.addAlias(this, this, name, opts);
 96              }
 97              get edgeArn() {
 98                  if (version === '$LATEST') {
 99                      throw new Error('$LATEST function version cannot be used for Lambda@Edge');
100                  }
101                  return this.functionArn;
102              }
103          }
104          return new Import(scope, id);
105      }
106      /**
107       * @stability stable
108       */
109      static fromVersionAttributes(scope, id, attrs) {
110          jsiiDeprecationWarnings._aws_cdk_aws_lambda_VersionAttributes(attrs);
111          class Import extends function_base_1.QualifiedFunctionBase {
112              constructor() {
113                  super(...arguments);
114                  this.version = attrs.version;
115                  this.lambda = attrs.lambda;
116                  this.functionName = `${attrs.lambda.functionName}:${attrs.version}`;
117                  this.functionArn = `${attrs.lambda.functionArn}:${attrs.version}`;
118                  this.grantPrincipal = attrs.lambda.grantPrincipal;
119                  this.role = attrs.lambda.role;
120                  this.qualifier = attrs.version;
121                  this.canCreatePermissions = this._isStackAccount();
122              }
123              addAlias(name, opts = {}) {
124                  return util_1.addAlias(this, this, name, opts);
125              }
126              get edgeArn() {
127                  if (attrs.version === '$LATEST') {
128                      throw new Error('$LATEST function version cannot be used for Lambda@Edge');
129                  }
130                  return this.functionArn;
131              }
132          }
133          return new Import(scope, id);
134      }
135      /**
136       * The principal this Lambda Function is running as.
137       *
138       * @stability stable
139       */
140      get grantPrincipal() {
141          return this.lambda.grantPrincipal;
142      }
143      /**
144       * The IAM role associated with this function.
145       *
146       * Undefined if the function was imported without a role.
147       *
148       * @stability stable
149       */
150      get role() {
151          return this.lambda.role;
152      }
153      /**
154       * Return the given named metric for this Function.
155       *
156       * @stability stable
157       */
158      metric(metricName, props = {}) {
159          // Metrics on Aliases need the "bare" function name, and the alias' ARN, this differs from the base behavior.
160          return super.metric(metricName, {
161              dimensions: {
162                  FunctionName: this.lambda.functionName,
163                  // construct the ARN from the underlying lambda so that alarms on an alias
164                  // don't cause a circular dependency with CodeDeploy
165                  // see: https://github.com/aws/aws-cdk/issues/2231
166                  Resource: `${this.lambda.functionArn}:${this.version}`,
167              },
168              ...props,
169          });
170      }
171      /**
172       * Defines an alias for this version.
173       *
174       * @param aliasName The name of the alias (e.g. "live").
175       * @param options Alias options.
176       * @stability stable
177       */
178      addAlias(aliasName, options = {}) {
179          jsiiDeprecationWarnings._aws_cdk_aws_lambda_AliasOptions(options);
180          return util_1.addAlias(this, this, aliasName, options);
181      }
182      /**
183       * The ARN of the version for Lambda@Edge.
184       *
185       * @stability stable
186       */
187      get edgeArn() {
188          // Validate first that this version can be used for Lambda@Edge
189          if (this.version === '$LATEST') {
190              throw new Error('$LATEST function version cannot be used for Lambda@Edge');
191          }
192          // Check compatibility at synthesis. It could be that the version was associated
193          // with a CloudFront distribution first and made incompatible afterwards.
194          return core_1.Lazy.string({
195              produce: () => {
196                  // Validate that the underlying function can be used for Lambda@Edge
197                  if (this.lambda instanceof function_1.Function) {
198                      this.lambda._checkEdgeCompatibility();
199                  }
200                  return this.functionArn;
201              },
202          });
203      }
204      /**
205       * Validate that the provisionedConcurrentExecutions makes sense
206       *
207       * Member must have value greater than or equal to 1
208       */
209      determineProvisionedConcurrency(props) {
210          if (!props.provisionedConcurrentExecutions) {
211              return undefined;
212          }
213          if (props.provisionedConcurrentExecutions <= 0) {
214              throw new Error('provisionedConcurrentExecutions must have value greater than or equal to 1');
215          }
216          return { provisionedConcurrentExecutions: props.provisionedConcurrentExecutions };
217      }
218  }
219  exports.Version = Version;
220  _a = JSII_RTTI_SYMBOL_1;
221  Version[_a] = { fqn: "@aws-cdk/aws-lambda.Version", version: "1.134.0" };
222  /**
223   * Given an opaque (token) ARN, returns a CloudFormation expression that extracts the
224   * qualifier (= version or alias) from the ARN.
225   *
226   * Version ARNs look like this:
227   *
228   *   arn:aws:lambda:region:account-id:function:function-name:qualifier
229   *
230   * ..which means that in order to extract the `qualifier` component from the ARN, we can
231   * split the ARN using ":" and select the component in index 7.
232   *
233   * @returns `FnSelect(7, FnSplit(':', arn))`
234   */
235  function extractQualifierFromArn(arn) {
236      return core_1.Fn.select(7, core_1.Fn.split(':', arn));
237  }
238  exports.extractQualifierFromArn = extractQualifierFromArn;
239  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFtYmRhLXZlcnNpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJsYW1iZGEtdmVyc2lvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSx3Q0FBd0Q7QUFJeEQseUNBQXNDO0FBQ3RDLG1EQUFtRTtBQUNuRSx5REFBZ0Q7QUFDaEQsaUNBQWtDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBOENsQyxNQUFhLE9BQVEsU0FBUSxxQ0FBcUI7Ozs7SUFrRWhELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBbUI7UUFDM0QsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQzs7Ozs7Ozs7O1FBSEEseUJBQW9CLEdBQUcsSUFBSSxDQUFDOztRQUs3QyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUM7UUFFM0IsTUFBTSxPQUFPLEdBQUcsSUFBSSw2QkFBVSxDQUFDLElBQUksRUFBRSxVQUFVLEVBQUU7WUFDL0MsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVO1lBQzVCLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVztZQUM5QixZQUFZLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxZQUFZO1lBQ3ZDLDRCQUE0QixFQUFFLElBQUksQ0FBQywrQkFBK0IsQ0FBQyxLQUFLLENBQUM7U0FDMUUsQ0FBQyxDQUFDO1FBRUgsSUFBSSxLQUFLLENBQUMsYUFBYSxFQUFFO1lBQ3ZCLE9BQU8sQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFO2dCQUM5QyxPQUFPLEVBQUUsb0JBQWEsQ0FBQyxPQUFPO2FBQy9CLENBQUMsQ0FBQztTQUNKO1FBRUQsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDO1FBQ25DLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQztRQUMvQixJQUFJLENBQUMsWUFBWSxHQUFHLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2xFLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLFdBQVcsQ0FBQztRQUVyQyxJQUFJLEtBQUssQ0FBQyxTQUFTLElBQUksS0FBSyxDQUFDLFNBQVMsSUFBSSxLQUFLLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxhQUFhLEtBQUssU0FBUyxFQUFFO1lBQ2hHLElBQUksQ0FBQyxvQkFBb0IsQ0FBQztnQkFDeEIsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTO2dCQUMxQixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVM7Z0JBQzFCLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVztnQkFDOUIsYUFBYSxFQUFFLEtBQUssQ0FBQyxhQUFhO2FBQ25DLENBQUMsQ0FBQztTQUNKO0tBQ0Y7Ozs7Ozs7OztJQTlGTSxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQWdCLEVBQUUsRUFBVSxFQUFFLFVBQWtCO1FBQzNFLE1BQU0sT0FBTyxHQUFHLHVCQUF1QixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3BELE1BQU0sTUFBTSxHQUFHLG1CQUFRLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxHQUFHLEVBQUUsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRTVFLE1BQU0sTUFBTyxTQUFRLHFDQUFxQjtZQUExQzs7Z0JBQ2tCLFlBQU8sR0FBRyxPQUFPLENBQUM7Z0JBQ2xCLFdBQU0sR0FBRyxNQUFNLENBQUM7Z0JBQ2hCLGlCQUFZLEdBQUcsR0FBRyxNQUFNLENBQUMsWUFBWSxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUNuRCxnQkFBVyxHQUFHLFVBQVUsQ0FBQztnQkFDekIsbUJBQWMsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDO2dCQUN2QyxTQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQztnQkFFaEIsY0FBUyxHQUFHLE9BQU8sQ0FBQztnQkFDcEIseUJBQW9CLEdBQUcsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBWW5FLENBQUM7WUFWUSxRQUFRLENBQUMsSUFBWSxFQUFFLE9BQXFCLEVBQUc7Z0JBQ3BELE9BQU8sZUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQzFDLENBQUM7WUFFRCxJQUFXLE9BQU87Z0JBQ2hCLElBQUksT0FBTyxLQUFLLFNBQVMsRUFBRTtvQkFDekIsTUFBTSxJQUFJLEtBQUssQ0FBQyx5REFBeUQsQ0FBQyxDQUFDO2lCQUM1RTtnQkFDRCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUM7WUFDMUIsQ0FBQztTQUNGO1FBQ0QsT0FBTyxJQUFJLE1BQU0sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7S0FDOUI7Ozs7SUFFTSxNQUFNLENBQUMscUJBQXFCLENBQUMsS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBd0I7O1FBQ3hGLE1BQU0sTUFBTyxTQUFRLHFDQUFxQjtZQUExQzs7Z0JBQ2tCLFlBQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDO2dCQUN4QixXQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztnQkFDdEIsaUJBQVksR0FBRyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsWUFBWSxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDL0QsZ0JBQVcsR0FBRyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsV0FBVyxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDN0QsbUJBQWMsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQztnQkFDN0MsU0FBSSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO2dCQUV0QixjQUFTLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztnQkFDMUIseUJBQW9CLEdBQUcsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBWW5FLENBQUM7WUFWUSxRQUFRLENBQUMsSUFBWSxFQUFFLE9BQXFCLEVBQUc7Z0JBQ3BELE9BQU8sZUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQzFDLENBQUM7WUFFRCxJQUFXLE9BQU87Z0JBQ2hCLElBQUksS0FBSyxDQUFDLE9BQU8sS0FBSyxTQUFTLEVBQUU7b0JBQy9CLE1BQU0sSUFBSSxLQUFLLENBQUMseURBQXlELENBQUMsQ0FBQztpQkFDNUU7Z0JBQ0QsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO1lBQzFCLENBQUM7U0FDRjtRQUNELE9BQU8sSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0tBQzlCOzs7Ozs7SUEyQ0QsSUFBVyxjQUFjO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUM7S0FDbkM7Ozs7Ozs7O0lBRUQsSUFBVyxJQUFJO1FBQ2IsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztLQUN6Qjs7Ozs7O0lBRU0sTUFBTSxDQUFDLFVBQWtCLEVBQUUsUUFBa0MsRUFBRTtRQUNwRSw2R0FBNkc7UUFDN0csT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRTtZQUM5QixVQUFVLEVBQUU7Z0JBQ1YsWUFBWSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWTtnQkFDdEMsMEVBQTBFO2dCQUMxRSxvREFBb0Q7Z0JBQ3BELGtEQUFrRDtnQkFDbEQsUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRTthQUN2RDtZQUNELEdBQUcsS0FBSztTQUNULENBQUMsQ0FBQztLQUNKOzs7Ozs7OztJQUdNLFFBQVEsQ0FBQyxTQUFpQixFQUFFLFVBQXdCLEVBQUc7O1FBQzVELE9BQU8sZUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0tBQ2pEOzs7Ozs7SUFFRCxJQUFXLE9BQU87UUFDaEIsK0RBQStEO1FBQy9ELElBQUksSUFBSSxDQUFDLE9BQU8sS0FBSyxTQUFTLEVBQUU7WUFDOUIsTUFBTSxJQUFJLEtBQUssQ0FBQyx5REFBeUQsQ0FBQyxDQUFDO1NBQzVFO1FBRUQsZ0ZBQWdGO1FBQ2hGLHlFQUF5RTtRQUN6RSxPQUFPLFdBQUksQ0FBQyxNQUFNLENBQUM7WUFDakIsT0FBTyxFQUFFLEdBQUcsRUFBRTtnQkFDWixvRUFBb0U7Z0JBQ3BFLElBQUksSUFBSSxDQUFDLE1BQU0sWUFBWSxtQkFBUSxFQUFFO29CQUNuQyxJQUFJLENBQUMsTUFBTSxDQUFDLHVCQUF1QixFQUFFLENBQUM7aUJBQ3ZDO2dCQUVELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQztZQUMxQixDQUFDO1NBQ0YsQ0FBQyxDQUFDO0tBQ0o7SUFFRDs7OztPQUlHO0lBQ0ssK0JBQStCLENBQUMsS0FBbUI7UUFDekQsSUFBSSxDQUFDLEtBQUssQ0FBQywrQkFBK0IsRUFBRTtZQUMxQyxPQUFPLFNBQVMsQ0FBQztTQUNsQjtRQUVELElBQUksS0FBSyxDQUFDLCtCQUErQixJQUFJLENBQUMsRUFBRTtZQUM5QyxNQUFNLElBQUksS0FBSyxDQUFDLDRFQUE0RSxDQUFDLENBQUM7U0FDL0Y7UUFFRCxPQUFPLEVBQUUsK0JBQStCLEVBQUUsS0FBSyxDQUFDLCtCQUErQixFQUFFLENBQUM7S0FDbkY7O0FBaktILDBCQWtLQzs7O0FBRUQ7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsU0FBZ0IsdUJBQXVCLENBQUMsR0FBVztJQUNqRCxPQUFPLFNBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLFNBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFDMUMsQ0FBQztBQUZELDBEQUVDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY2xvdWR3YXRjaCBmcm9tICdAYXdzLWNkay9hd3MtY2xvdWR3YXRjaCc7XG5pbXBvcnQgeyBGbiwgTGF6eSwgUmVtb3ZhbFBvbGljeSB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBBbGlhcywgQWxpYXNPcHRpb25zIH0gZnJvbSAnLi9hbGlhcyc7XG5pbXBvcnQgeyBFdmVudEludm9rZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuL2V2ZW50LWludm9rZS1jb25maWcnO1xuaW1wb3J0IHsgRnVuY3Rpb24gfSBmcm9tICcuL2Z1bmN0aW9uJztcbmltcG9ydCB7IElGdW5jdGlvbiwgUXVhbGlmaWVkRnVuY3Rpb25CYXNlIH0gZnJvbSAnLi9mdW5jdGlvbi1iYXNlJztcbmltcG9ydCB7IENmblZlcnNpb24gfSBmcm9tICcuL2xhbWJkYS5nZW5lcmF0ZWQnO1xuaW1wb3J0IHsgYWRkQWxpYXMgfSBmcm9tICcuL3V0aWwnO1xuXG5leHBvcnQgaW50ZXJmYWNlIElWZXJzaW9uIGV4dGVuZHMgSUZ1bmN0aW9uIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgdmVyc2lvbjogc3RyaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGxhbWJkYTogSUZ1bmN0aW9uO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSBlZGdlQXJuOiBzdHJpbmc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBhZGRBbGlhcyhhbGlhc05hbWU6IHN0cmluZywgb3B0aW9ucz86IEFsaWFzT3B0aW9ucyk6IEFsaWFzO1xufVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBpbnRlcmZhY2UgVmVyc2lvbk9wdGlvbnMgZXh0ZW5kcyBFdmVudEludm9rZUNvbmZpZ09wdGlvbnMge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSBjb2RlU2hhMjU2Pzogc3RyaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgcHJvdmlzaW9uZWRDb25jdXJyZW50RXhlY3V0aW9ucz86IG51bWJlcjtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IHJlbW92YWxQb2xpY3k/OiBSZW1vdmFsUG9saWN5O1xufVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG5leHBvcnQgaW50ZXJmYWNlIFZlcnNpb25Qcm9wcyBleHRlbmRzIFZlcnNpb25PcHRpb25zIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSBsYW1iZGE6IElGdW5jdGlvbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWZXJzaW9uQXR0cmlidXRlcyB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSB2ZXJzaW9uOiBzdHJpbmc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgbGFtYmRhOiBJRnVuY3Rpb247XG59XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG5leHBvcnQgY2xhc3MgVmVyc2lvbiBleHRlbmRzIFF1YWxpZmllZEZ1bmN0aW9uQmFzZSBpbXBsZW1lbnRzIElWZXJzaW9uIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHN0YXRpYyBmcm9tVmVyc2lvbkFybihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCB2ZXJzaW9uQXJuOiBzdHJpbmcpOiBJVmVyc2lvbiB7XG4gICAgY29uc3QgdmVyc2lvbiA9IGV4dHJhY3RRdWFsaWZpZXJGcm9tQXJuKHZlcnNpb25Bcm4pO1xuICAgIGNvbnN0IGxhbWJkYSA9IEZ1bmN0aW9uLmZyb21GdW5jdGlvbkFybihzY29wZSwgYCR7aWR9RnVuY3Rpb25gLCB2ZXJzaW9uQXJuKTtcblxuICAgIGNsYXNzIEltcG9ydCBleHRlbmRzIFF1YWxpZmllZEZ1bmN0aW9uQmFzZSBpbXBsZW1lbnRzIElWZXJzaW9uIHtcbiAgICAgIHB1YmxpYyByZWFkb25seSB2ZXJzaW9uID0gdmVyc2lvbjtcbiAgICAgIHB1YmxpYyByZWFkb25seSBsYW1iZGEgPSBsYW1iZGE7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgZnVuY3Rpb25OYW1lID0gYCR7bGFtYmRhLmZ1bmN0aW9uTmFtZX06JHt2ZXJzaW9ufWA7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgZnVuY3Rpb25Bcm4gPSB2ZXJzaW9uQXJuO1xuICAgICAgcHVibGljIHJlYWRvbmx5IGdyYW50UHJpbmNpcGFsID0gbGFtYmRhLmdyYW50UHJpbmNpcGFsO1xuICAgICAgcHVibGljIHJlYWRvbmx5IHJvbGUgPSBsYW1iZGEucm9sZTtcblxuICAgICAgcHJvdGVjdGVkIHJlYWRvbmx5IHF1YWxpZmllciA9IHZlcnNpb247XG4gICAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2FuQ3JlYXRlUGVybWlzc2lvbnMgPSB0aGlzLl9pc1N0YWNrQWNjb3VudCgpO1xuXG4gICAgICBwdWJsaWMgYWRkQWxpYXMobmFtZTogc3RyaW5nLCBvcHRzOiBBbGlhc09wdGlvbnMgPSB7IH0pOiBBbGlhcyB7XG4gICAgICAgIHJldHVybiBhZGRBbGlhcyh0aGlzLCB0aGlzLCBuYW1lLCBvcHRzKTtcbiAgICAgIH1cblxuICAgICAgcHVibGljIGdldCBlZGdlQXJuKCk6IHN0cmluZyB7XG4gICAgICAgIGlmICh2ZXJzaW9uID09PSAnJExBVEVTVCcpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJyRMQVRFU1QgZnVuY3Rpb24gdmVyc2lvbiBjYW5ub3QgYmUgdXNlZCBmb3IgTGFtYmRhQEVkZ2UnKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5mdW5jdGlvbkFybjtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG5ldyBJbXBvcnQoc2NvcGUsIGlkKTtcbiAgfVxuXG4gIHB1YmxpYyBzdGF0aWMgZnJvbVZlcnNpb25BdHRyaWJ1dGVzKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIGF0dHJzOiBWZXJzaW9uQXR0cmlidXRlcyk6IElWZXJzaW9uIHtcbiAgICBjbGFzcyBJbXBvcnQgZXh0ZW5kcyBRdWFsaWZpZWRGdW5jdGlvbkJhc2UgaW1wbGVtZW50cyBJVmVyc2lvbiB7XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgdmVyc2lvbiA9IGF0dHJzLnZlcnNpb247XG4gICAgICBwdWJsaWMgcmVhZG9ubHkgbGFtYmRhID0gYXR0cnMubGFtYmRhO1xuICAgICAgcHVibGljIHJlYWRvbmx5IGZ1bmN0aW9uTmFtZSA9IGAke2F0dHJzLmxhbWJkYS5mdW5jdGlvbk5hbWV9OiR7YXR0cnMudmVyc2lvbn1gO1xuICAgICAgcHVibGljIHJlYWRvbmx5IGZ1bmN0aW9uQXJuID0gYCR7YXR0cnMubGFtYmRhLmZ1bmN0aW9uQXJufToke2F0dHJzLnZlcnNpb259YDtcbiAgICAgIHB1YmxpYyByZWFkb25seSBncmFudFByaW5jaXBhbCA9IGF0dHJzLmxhbWJkYS5ncmFudFByaW5jaXBhbDtcbiAgICAgIHB1YmxpYyByZWFkb25seSByb2xlID0gYXR0cnMubGFtYmRhLnJvbGU7XG5cbiAgICAgIHByb3RlY3RlZCByZWFkb25seSBxdWFsaWZpZXIgPSBhdHRycy52ZXJzaW9uO1xuICAgICAgcHJvdGVjdGVkIHJlYWRvbmx5IGNhbkNyZWF0ZVBlcm1pc3Npb25zID0gdGhpcy5faXNTdGFja0FjY291bnQoKTtcblxuICAgICAgcHVibGljIGFkZEFsaWFzKG5hbWU6IHN0cmluZywgb3B0czogQWxpYXNPcHRpb25zID0geyB9KTogQWxpYXMge1xuICAgICAgICByZXR1cm4gYWRkQWxpYXModGhpcywgdGhpcywgbmFtZSwgb3B0cyk7XG4gICAgICB9XG5cbiAgICAgIHB1YmxpYyBnZXQgZWRnZUFybigpOiBzdHJpbmcge1xuICAgICAgICBpZiAoYXR0cnMudmVyc2lvbiA9PT0gJyRMQVRFU1QnKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCckTEFURVNUIGZ1bmN0aW9uIHZlcnNpb24gY2Fubm90IGJlIHVzZWQgZm9yIExhbWJkYUBFZGdlJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuZnVuY3Rpb25Bcm47XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuZXcgSW1wb3J0KHNjb3BlLCBpZCk7XG4gIH1cblxuICBwdWJsaWMgcmVhZG9ubHkgdmVyc2lvbjogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgbGFtYmRhOiBJRnVuY3Rpb247XG4gIHB1YmxpYyByZWFkb25seSBmdW5jdGlvbkFybjogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgZnVuY3Rpb25OYW1lOiBzdHJpbmc7XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHF1YWxpZmllcjogc3RyaW5nO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2FuQ3JlYXRlUGVybWlzc2lvbnMgPSB0cnVlO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBWZXJzaW9uUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5sYW1iZGEgPSBwcm9wcy5sYW1iZGE7XG5cbiAgICBjb25zdCB2ZXJzaW9uID0gbmV3IENmblZlcnNpb24odGhpcywgJ1Jlc291cmNlJywge1xuICAgICAgY29kZVNoYTI1NjogcHJvcHMuY29kZVNoYTI1NixcbiAgICAgIGRlc2NyaXB0aW9uOiBwcm9wcy5kZXNjcmlwdGlvbixcbiAgICAgIGZ1bmN0aW9uTmFtZTogcHJvcHMubGFtYmRhLmZ1bmN0aW9uTmFtZSxcbiAgICAgIHByb3Zpc2lvbmVkQ29uY3VycmVuY3lDb25maWc6IHRoaXMuZGV0ZXJtaW5lUHJvdmlzaW9uZWRDb25jdXJyZW5jeShwcm9wcyksXG4gICAgfSk7XG5cbiAgICBpZiAocHJvcHMucmVtb3ZhbFBvbGljeSkge1xuICAgICAgdmVyc2lvbi5hcHBseVJlbW92YWxQb2xpY3kocHJvcHMucmVtb3ZhbFBvbGljeSwge1xuICAgICAgICBkZWZhdWx0OiBSZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLnZlcnNpb24gPSB2ZXJzaW9uLmF0dHJWZXJzaW9uO1xuICAgIHRoaXMuZnVuY3Rpb25Bcm4gPSB2ZXJzaW9uLnJlZjtcbiAgICB0aGlzLmZ1bmN0aW9uTmFtZSA9IGAke3RoaXMubGFtYmRhLmZ1bmN0aW9uTmFtZX06JHt0aGlzLnZlcnNpb259YDtcbiAgICB0aGlzLnF1YWxpZmllciA9IHZlcnNpb24uYXR0clZlcnNpb247XG5cbiAgICBpZiAocHJvcHMub25GYWlsdXJlIHx8IHByb3BzLm9uU3VjY2VzcyB8fCBwcm9wcy5tYXhFdmVudEFnZSB8fCBwcm9wcy5yZXRyeUF0dGVtcHRzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMuY29uZmlndXJlQXN5bmNJbnZva2Uoe1xuICAgICAgICBvbkZhaWx1cmU6IHByb3BzLm9uRmFpbHVyZSxcbiAgICAgICAgb25TdWNjZXNzOiBwcm9wcy5vblN1Y2Nlc3MsXG4gICAgICAgIG1heEV2ZW50QWdlOiBwcm9wcy5tYXhFdmVudEFnZSxcbiAgICAgICAgcmV0cnlBdHRlbXB0czogcHJvcHMucmV0cnlBdHRlbXB0cyxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBnZXQgZ3JhbnRQcmluY2lwYWwoKSB7XG4gICAgcmV0dXJuIHRoaXMubGFtYmRhLmdyYW50UHJpbmNpcGFsO1xuICB9XG5cbiAgcHVibGljIGdldCByb2xlKCkge1xuICAgIHJldHVybiB0aGlzLmxhbWJkYS5yb2xlO1xuICB9XG5cbiAgcHVibGljIG1ldHJpYyhtZXRyaWNOYW1lOiBzdHJpbmcsIHByb3BzOiBjbG91ZHdhdGNoLk1ldHJpY09wdGlvbnMgPSB7fSk6IGNsb3Vkd2F0Y2guTWV0cmljIHtcbiAgICAvLyBNZXRyaWNzIG9uIEFsaWFzZXMgbmVlZCB0aGUgXCJiYXJlXCIgZnVuY3Rpb24gbmFtZSwgYW5kIHRoZSBhbGlhcycgQVJOLCB0aGlzIGRpZmZlcnMgZnJvbSB0aGUgYmFzZSBiZWhhdmlvci5cbiAgICByZXR1cm4gc3VwZXIubWV0cmljKG1ldHJpY05hbWUsIHtcbiAgICAgIGRpbWVuc2lvbnM6IHtcbiAgICAgICAgRnVuY3Rpb25OYW1lOiB0aGlzLmxhbWJkYS5mdW5jdGlvbk5hbWUsXG4gICAgICAgIC8vIGNvbnN0cnVjdCB0aGUgQVJOIGZyb20gdGhlIHVuZGVybHlpbmcgbGFtYmRhIHNvIHRoYXQgYWxhcm1zIG9uIGFuIGFsaWFzXG4gICAgICAgIC8vIGRvbid0IGNhdXNlIGEgY2lyY3VsYXIgZGVwZW5kZW5jeSB3aXRoIENvZGVEZXBsb3lcbiAgICAgICAgLy8gc2VlOiBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvaXNzdWVzLzIyMzFcbiAgICAgICAgUmVzb3VyY2U6IGAke3RoaXMubGFtYmRhLmZ1bmN0aW9uQXJufToke3RoaXMudmVyc2lvbn1gLFxuICAgICAgfSxcbiAgICAgIC4uLnByb3BzLFxuICAgIH0pO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBhZGRBbGlhcyhhbGlhc05hbWU6IHN0cmluZywgb3B0aW9uczogQWxpYXNPcHRpb25zID0geyB9KTogQWxpYXMge1xuICAgIHJldHVybiBhZGRBbGlhcyh0aGlzLCB0aGlzLCBhbGlhc05hbWUsIG9wdGlvbnMpO1xuICB9XG5cbiAgcHVibGljIGdldCBlZGdlQXJuKCk6IHN0cmluZyB7XG4gICAgLy8gVmFsaWRhdGUgZmlyc3QgdGhhdCB0aGlzIHZlcnNpb24gY2FuIGJlIHVzZWQgZm9yIExhbWJkYUBFZGdlXG4gICAgaWYgKHRoaXMudmVyc2lvbiA9PT0gJyRMQVRFU1QnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJyRMQVRFU1QgZnVuY3Rpb24gdmVyc2lvbiBjYW5ub3QgYmUgdXNlZCBmb3IgTGFtYmRhQEVkZ2UnKTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBjb21wYXRpYmlsaXR5IGF0IHN5bnRoZXNpcy4gSXQgY291bGQgYmUgdGhhdCB0aGUgdmVyc2lvbiB3YXMgYXNzb2NpYXRlZFxuICAgIC8vIHdpdGggYSBDbG91ZEZyb250IGRpc3RyaWJ1dGlvbiBmaXJzdCBhbmQgbWFkZSBpbmNvbXBhdGlibGUgYWZ0ZXJ3YXJkcy5cbiAgICByZXR1cm4gTGF6eS5zdHJpbmcoe1xuICAgICAgcHJvZHVjZTogKCkgPT4ge1xuICAgICAgICAvLyBWYWxpZGF0ZSB0aGF0IHRoZSB1bmRlcmx5aW5nIGZ1bmN0aW9uIGNhbiBiZSB1c2VkIGZvciBMYW1iZGFARWRnZVxuICAgICAgICBpZiAodGhpcy5sYW1iZGEgaW5zdGFuY2VvZiBGdW5jdGlvbikge1xuICAgICAgICAgIHRoaXMubGFtYmRhLl9jaGVja0VkZ2VDb21wYXRpYmlsaXR5KCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcy5mdW5jdGlvbkFybjtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgdGhhdCB0aGUgcHJvdmlzaW9uZWRDb25jdXJyZW50RXhlY3V0aW9ucyBtYWtlcyBzZW5zZVxuICAgKlxuICAgKiBNZW1iZXIgbXVzdCBoYXZlIHZhbHVlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAxXG4gICAqL1xuICBwcml2YXRlIGRldGVybWluZVByb3Zpc2lvbmVkQ29uY3VycmVuY3kocHJvcHM6IFZlcnNpb25Qcm9wcyk6IENmblZlcnNpb24uUHJvdmlzaW9uZWRDb25jdXJyZW5jeUNvbmZpZ3VyYXRpb25Qcm9wZXJ0eSB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCFwcm9wcy5wcm92aXNpb25lZENvbmN1cnJlbnRFeGVjdXRpb25zKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGlmIChwcm9wcy5wcm92aXNpb25lZENvbmN1cnJlbnRFeGVjdXRpb25zIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigncHJvdmlzaW9uZWRDb25jdXJyZW50RXhlY3V0aW9ucyBtdXN0IGhhdmUgdmFsdWUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIDEnKTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBwcm92aXNpb25lZENvbmN1cnJlbnRFeGVjdXRpb25zOiBwcm9wcy5wcm92aXNpb25lZENvbmN1cnJlbnRFeGVjdXRpb25zIH07XG4gIH1cbn1cblxuLyoqXG4gKiBHaXZlbiBhbiBvcGFxdWUgKHRva2VuKSBBUk4sIHJldHVybnMgYSBDbG91ZEZvcm1hdGlvbiBleHByZXNzaW9uIHRoYXQgZXh0cmFjdHMgdGhlXG4gKiBxdWFsaWZpZXIgKD0gdmVyc2lvbiBvciBhbGlhcykgZnJvbSB0aGUgQVJOLlxuICpcbiAqIFZlcnNpb24gQVJOcyBsb29rIGxpa2UgdGhpczpcbiAqXG4gKiAgIGFybjphd3M6bGFtYmRhOnJlZ2lvbjphY2NvdW50LWlkOmZ1bmN0aW9uOmZ1bmN0aW9uLW5hbWU6cXVhbGlmaWVyXG4gKlxuICogLi53aGljaCBtZWFucyB0aGF0IGluIG9yZGVyIHRvIGV4dHJhY3QgdGhlIGBxdWFsaWZpZXJgIGNvbXBvbmVudCBmcm9tIHRoZSBBUk4sIHdlIGNhblxuICogc3BsaXQgdGhlIEFSTiB1c2luZyBcIjpcIiBhbmQgc2VsZWN0IHRoZSBjb21wb25lbnQgaW4gaW5kZXggNy5cbiAqXG4gKiBAcmV0dXJucyBgRm5TZWxlY3QoNywgRm5TcGxpdCgnOicsIGFybikpYFxuICovXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFF1YWxpZmllckZyb21Bcm4oYXJuOiBzdHJpbmcpIHtcbiAgcmV0dXJuIEZuLnNlbGVjdCg3LCBGbi5zcGxpdCgnOicsIGFybikpO1xufVxuIl19