├── .gitignore ├── LICENSE.md ├── README.md ├── cfn ├── json │ ├── create-and-use-custom-resource.json │ ├── create-custom-resource.json │ └── use-custom-resource.json └── yml │ ├── create-and-use-custom-resource.yml │ ├── create-custom-resource.yml │ └── use-custom-resource.yml └── lambda ├── java ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ └── java │ └── com │ └── stelligent │ └── customresource │ └── CustomResourceHandler.java ├── nodejs ├── .eslintrc.yml ├── customresource.js ├── package-lock.json └── package.json └── python ├── .pylintrc ├── Pipfile ├── Pipfile.lock └── customresource.py /.gitignore: -------------------------------------------------------------------------------- 1 | lambda/java/target 2 | lambda/java/dependency-reduced-pom.xml 3 | .vscode/ 4 | *.pyc 5 | .gradle/ 6 | */java/build/ 7 | node_modules/ 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2020 Stelligent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cloudformation-custom-resources 2 | 3 | This repository contains stub code for setting up Lambda-backed CloudFormation Custom Resources. 4 | 5 | ### What is a custom resource? 6 | 7 | CloudFormation has lots of defined resources that you can use to provision AWS resources. However, if you want to provision an AWS resource that CloudFormation doesn't support yet, or if you want to include some complicated logic during your CloudFormation stack creation / update / deletion, you can use a _custom resource_ to do that easily. Custom resources are basically just Lambda functions that get called by CloudFormation. While not complicated, they do require a bit of configuration to get going. This repository is design to kickstart building custom resources, having the scaffolding for Python, Node.js, and Java functions (_Ruby coming soon!_) and examples in both YML and JSON. 8 | 9 | ### How do I use this repository? 10 | 11 | This repository contains a superset of what you'll need to get started using custom resources. It has sample templates in both JSON and YML formats (in the `cfn/` dir), as well as the scaffolding for Lambda functions in Node.js, Python, and Java (in the `lambdas/` dir). You can pick whichever one is the best choice for you and run with it. 12 | 13 | For the sample templates, there are two flavors available: create-and-use of a custom resource in a single template, or separate templates for creation and use of the custom resouce. If you're going to be re-using your custom resource from a lot of other templates, you'll probably want to use separate templates for each, as having them in the same template will create a copy of the Lambda function for each stack. While the costs associated with that are negligible, if you're provisioning a lot of stacks it can make a mess pretty easily. 14 | 15 | Once you've decided on which languages you'll want to use, you simply have to implement the logic for the create, read, and update actions that CloudFormation will send you. Depending on what your custom resource does, you may not need to implement them all, or you may re-use the logic for multiple actions. The documentation for CloudFormation custom resources is [here](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref.html), and gives details on the request object your code should expect, and the responses that CloudFormation accepts. 16 | 17 | ### Running the templates 18 | 19 | _Note_: these directions assume you have the AWS CLI [installed](http://docs.aws.amazon.com/cli/latest/userguide/installing.html) and [configured](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html). 20 | 21 | These templates are designed to load the Lambda functions from an S3 bucket. While it is possible to keep the entire Lambda code inside the template, that is a road that gets painful very quickly so it's best avoid. So there first thing you'll need to do is to create a bucket to stage your Lambda function code in: 22 | 23 | aws s3 mb s3://whatever-you-wanna-call-your-bucket 24 | 25 | Once that's in place, you can use the following commands to zip, upload, and then kick off the CloudFormation templates. These examples are for the Python flavor, but are easily adaptable to Node.js or Java: 26 | 27 | create_stack=create-custom-rsc 28 | use_stack=use-custom-rsc 29 | bucket=whatever-you-wanna-call-your-bucket 30 | 31 | # if you're using Node.js or Java, change this to match that directory name 32 | pushd lambda/python 33 | rm -rf tmp 34 | mkdir -p tmp 35 | zip tmp/custom-resource.zip customresource.* 36 | aws s3 cp tmp/custom-resource.zip s3://${bucket}/custom-resource.zip 37 | rm -rf tmp 38 | popd 39 | # And then change the LambdaRuntime parameter 40 | aws cloudformation create-stack \ 41 | --stack-name $create_stack \ 42 | --template-body file://cfn/json/create-custom-resource.json \ 43 | --capabilities CAPABILITY_IAM \ 44 | --disable-rollback \ 45 | --parameters \ 46 | ParameterKey="S3Bucket",ParameterValue="${bucket}" \ 47 | ParameterKey="S3Key",ParameterValue="custom-resource.zip" \ 48 | ParameterKey="ModuleName",ParameterValue="customresource" \ 49 | ParameterKey="LambdaRuntime",ParameterValue="python2.7" 50 | 51 | # the sleep call is here if you're running this in a script -- it takes about that long for the Lambda function to deploy. 52 | # if you're running this by hand, you can skip that part. 53 | sleep 30 54 | custom_function_arn=$(aws cloudformation describe-stacks --stack-name $create_stack --query Stacks[*].Outputs[?OutputKey==\'CustomFunctionArn\'].OutputValue --output text) 55 | 56 | aws cloudformation create-stack \ 57 | --stack-name $use_stack \ 58 | --template-body file://cfn/json/use-custom-resource.json \ 59 | --disable-rollback \ 60 | --parameters \ 61 | ParameterKey="CustomFunctionArn",ParameterValue="$custom_function_arn" 62 | 63 | #### But, Java. 64 | 65 | If you're looking to get the Java function running, the concepts are the same but the steps differ slightly because everything is harder in Java. :) Instead of making a zip file, we'll use maven to download all the dependencies and create a jar file, which we'll then upload into S3. You'll also need to include an extra parameter, `HandlerName`, so that Lambda knows which class and method to call. Here's an example of how you build and deploy the Java function: 66 | 67 | pushd lambda/java 68 | rm -rf target 69 | mvn package 70 | aws s3 cp target/customresource-1.0.0.jar s3://${bucket}/customresource-1.0.0.jar 71 | mvn clean 72 | popd 73 | aws cloudformation create-stack \ 74 | --stack-name $create_stack \ 75 | --template-body file://cfn/json/create-custom-resource.json \ 76 | --capabilities CAPABILITY_IAM \ 77 | --disable-rollback \ 78 | --parameters \ 79 | ParameterKey="S3Bucket",ParameterValue="${bucket}" \ 80 | ParameterKey="S3Key",ParameterValue="customresource-1.0.0.jar" \ 81 | ParameterKey="ModuleName",ParameterValue="com.stelligent.customresource" \ 82 | ParameterKey="LambdaRuntime",ParameterValue="java8" \ 83 | ParameterKey="HandlerName",ParameterValue="CustomResourceHandler" 84 | 85 | 86 | Looking up the ARN of the function and creating a stack that uses the Java Lambda function is exactly the same. 87 | 88 | ### Problems? 89 | 90 | We did our best to test out these examples, but if you notice any problems with any of them, we would be much obliged if you could let us know by [opening an issue](https://github.com/stelligent/cloudformation-custom-resources/issues)! 91 | 92 | ### Special Thanks 93 | 94 | In true CloudFormation fashion, most of this work was built by finding something that kinda did what we wanted and then tweaking it until it worked. A lot of the concepts were based off the [Looking Up Amazon Machine Image IDs](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/walkthrough-custom-resources-lambda-lookup-amiids.html) from the official AWS documentation. 95 | 96 | Also, I wanted to extend a special thank you to @dghadge for putting together the Java Lambda function and to @lhitchon for providing very helpful advice about the Python function. 97 | -------------------------------------------------------------------------------- /cfn/json/create-and-use-custom-resource.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion" : "2010-09-09", 3 | 4 | "Description" : "AWS CloudFormation to set up a custom CloudFormation resource with Lambda, and then call it in the same template.", 5 | 6 | "Parameters": { 7 | "LambdaRuntime" : { 8 | "Description" : "The Lambda runtime to use", 9 | "Type" : "String", 10 | "AllowedValues" : ["nodejs", "nodejs4.3", "nodejs6.10", "nodejs8.10", "java8", "python2.7", "python3.6", 11 | "dotnetcore1.0", "dotnetcore2.0", "dotnetcore2.1", "nodejs4.3-edge", "go1.x"] 12 | }, 13 | "HandlerName" : { 14 | "Description" : "The name of the lambda handler", 15 | "Type" : "String", 16 | "Default" : "handler" 17 | }, 18 | "ModuleName" : { 19 | "Description" : "The name of the JavaScript file", 20 | "Type" : "String", 21 | "Default" : "customresource" 22 | }, 23 | "S3Bucket" : { 24 | "Description" : "The name of the bucket that contains your packaged source", 25 | "Type" : "String" 26 | }, 27 | "S3Key" : { 28 | "Description" : "The name of the ZIP package", 29 | "Type" : "String", 30 | "Default" : "custom-resource.zip" 31 | } 32 | }, 33 | "Resources" : { 34 | "CustomFunction": { 35 | "Type": "AWS::Lambda::Function", 36 | "Properties": { 37 | "Code": { 38 | "S3Bucket": { "Ref": "S3Bucket" }, 39 | "S3Key": { "Ref": "S3Key" } 40 | }, 41 | "Handler": { "Fn::Join" : [ "", [{ "Ref": "ModuleName" },".",{ "Ref": "HandlerName" }] ] }, 42 | "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, 43 | "Runtime": { "Ref" : "LambdaRuntime"}, 44 | "Timeout": "30" 45 | } 46 | }, 47 | 48 | "LambdaExecutionRole": { 49 | "Type": "AWS::IAM::Role", 50 | "Properties": { 51 | "AssumeRolePolicyDocument": { 52 | "Version": "2012-10-17", 53 | "Statement": [{ 54 | "Effect": "Allow", 55 | "Principal": {"Service": ["lambda.amazonaws.com"]}, 56 | "Action": ["sts:AssumeRole"] 57 | }] 58 | }, 59 | "Path": "/", 60 | "Policies": [{ 61 | "PolicyName": "root", 62 | "PolicyDocument": { 63 | "Version": "2012-10-17", 64 | "Statement": [{ 65 | "Effect": "Allow", 66 | "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"], 67 | "Resource": "arn:aws:logs:*:*:*" 68 | }, 69 | { 70 | "Effect": "Allow", 71 | "Action": ["ec2:DescribeImages"], 72 | "Resource": "*" 73 | }] 74 | } 75 | }] 76 | } 77 | }, 78 | "CustomResource": { 79 | "Type": "Custom::CustomResource", 80 | "Properties": { 81 | "ServiceToken": { "Fn::GetAtt" : ["CustomFunction", "Arn"] }, 82 | "ParameterOne": "Parameter to pass into Custom Lambda Function" 83 | } 84 | } 85 | }, 86 | "Outputs" : { 87 | "Message" : { 88 | "Description": "The message from the custom resource.", 89 | "Value" : { "Fn::GetAtt": [ "CustomResource", "Message" ] } 90 | }, 91 | "CustomFunctionArn" : { 92 | "Description": "The arn of the custom resource function.", 93 | "Value" : { "Fn::GetAtt" : ["CustomFunction", "Arn"] } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /cfn/json/create-custom-resource.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion" : "2010-09-09", 3 | 4 | "Description" : "AWS CloudFormation to set up a custom CloudFormation resource with Lambda.", 5 | 6 | "Parameters": { 7 | "LambdaRuntime" : { 8 | "Description" : "The Lambda runtime to use", 9 | "Type" : "String", 10 | "AllowedValues" : ["nodejs", "nodejs4.3", "nodejs6.10", "nodejs8.10", "java8", "python2.7", "python3.6", 11 | "dotnetcore1.0", "dotnetcore2.0", "dotnetcore2.1", "nodejs4.3-edge", "go1.x"] 12 | }, 13 | "ModuleName" : { 14 | "Description" : "The name of the JavaScript file", 15 | "Type" : "String", 16 | "Default" : "customresource" 17 | }, 18 | "HandlerName" : { 19 | "Description" : "The name of the lambda handler", 20 | "Type" : "String", 21 | "Default" : "handler" 22 | }, 23 | "S3Bucket" : { 24 | "Description" : "The name of the bucket that contains your packaged source", 25 | "Type" : "String" 26 | }, 27 | "S3Key" : { 28 | "Description" : "The name of the ZIP package", 29 | "Type" : "String", 30 | "Default" : "custom-resource.zip" 31 | } 32 | }, 33 | 34 | "Resources" : { 35 | "CustomFunction": { 36 | "Type": "AWS::Lambda::Function", 37 | "Properties": { 38 | "Code": { 39 | "S3Bucket": { "Ref": "S3Bucket" }, 40 | "S3Key": { "Ref": "S3Key" } 41 | }, 42 | "Handler": { "Fn::Join" : [ "", [{ "Ref": "ModuleName" },".",{ "Ref": "HandlerName" }] ] }, 43 | "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, 44 | "Runtime": { "Ref" : "LambdaRuntime"}, 45 | "Timeout": "30" 46 | } 47 | }, 48 | 49 | "LambdaExecutionRole": { 50 | "Type": "AWS::IAM::Role", 51 | "Properties": { 52 | "AssumeRolePolicyDocument": { 53 | "Version": "2012-10-17", 54 | "Statement": [{ 55 | "Effect": "Allow", 56 | "Principal": {"Service": ["lambda.amazonaws.com"]}, 57 | "Action": ["sts:AssumeRole"] 58 | }] 59 | }, 60 | "Path": "/", 61 | "Policies": [{ 62 | "PolicyName": "root", 63 | "PolicyDocument": { 64 | "Version": "2012-10-17", 65 | "Statement": [{ 66 | "Effect": "Allow", 67 | "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"], 68 | "Resource": "arn:aws:logs:*:*:*" 69 | }, 70 | { 71 | "Effect": "Allow", 72 | "Action": ["ec2:DescribeImages"], 73 | "Resource": "*" 74 | }] 75 | } 76 | }] 77 | } 78 | } 79 | }, 80 | "Outputs" : { 81 | "CustomFunctionArn" : { 82 | "Description": "The arn of the custom resource function.", 83 | "Value" : { "Fn::GetAtt" : ["CustomFunction", "Arn"] } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /cfn/json/use-custom-resource.json: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion" : "2010-09-09", 3 | 4 | "Description" : "AWS CloudFormation to consume a custom CloudFormation resource with Lambda. It calls a previously created CloudFormation Custom Resource Lambda and puts the result into the output of the stack.", 5 | "Parameters" : { 6 | "CustomFunctionArn" : { 7 | "Type" : "String", 8 | "Description": "the ARN of the custom resource (this is an output of the previous CloudFormation stack" 9 | } 10 | }, 11 | "Resources" : { 12 | "CustomResource": { 13 | "Type": "Custom::CustomResource", 14 | "Properties": { 15 | "ServiceToken": { "Ref" : "CustomFunctionArn" }, 16 | "ParameterOne": "Parameter to pass into Custom Lambda Function" 17 | } 18 | } 19 | }, 20 | "Outputs" : { 21 | "Message" : { 22 | "Description": "The message from the custom resource.", 23 | "Value" : { "Fn::GetAtt": [ "CustomResource", "Message" ] } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cfn/yml/create-and-use-custom-resource.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: AWS CloudFormation to set up a custom CloudFormation resource with Lambda, 3 | and then call it in the same template. 4 | Parameters: 5 | LambdaRuntime: 6 | Description: The Lambda runtime to use 7 | Type: String 8 | AllowedValues: 9 | - nodejs 10 | - nodejs4.3 11 | - nodejs6.10 12 | - nodejs8.10 13 | - java8 14 | - python2.7 15 | - python3.6 16 | - dotnetcore1.0 17 | - dotnetcore2.0 18 | - dotnetcore2.1 19 | - nodejs4.3-edge 20 | - go1.x 21 | HandlerName: 22 | Description: The name of the lambda handler 23 | Type: String 24 | Default: handler 25 | ModuleName: 26 | Description: The name of the JavaScript file 27 | Type: String 28 | Default: customresource 29 | S3Bucket: 30 | Description: The name of the bucket that contains your packaged source 31 | Type: String 32 | S3Key: 33 | Description: The name of the ZIP package 34 | Type: String 35 | Default: custom-resource.zip 36 | Resources: 37 | CustomFunction: 38 | Type: AWS::Lambda::Function 39 | Properties: 40 | Code: 41 | S3Bucket: !Ref 'S3Bucket' 42 | S3Key: !Ref 'S3Key' 43 | Handler: !Join ['', [!Ref 'ModuleName', ., !Ref 'HandlerName']] 44 | Role: !GetAtt 'LambdaExecutionRole.Arn' 45 | Runtime: !Ref 'LambdaRuntime' 46 | Timeout: '30' 47 | LambdaExecutionRole: 48 | Type: AWS::IAM::Role 49 | Properties: 50 | AssumeRolePolicyDocument: 51 | Version: '2012-10-17' 52 | Statement: 53 | - Effect: Allow 54 | Principal: 55 | Service: 56 | - lambda.amazonaws.com 57 | Action: 58 | - sts:AssumeRole 59 | Path: / 60 | Policies: 61 | - PolicyName: root 62 | PolicyDocument: 63 | Version: '2012-10-17' 64 | Statement: 65 | - Effect: Allow 66 | Action: 67 | - logs:CreateLogGroup 68 | - logs:CreateLogStream 69 | - logs:PutLogEvents 70 | Resource: arn:aws:logs:*:*:* 71 | - Effect: Allow 72 | Action: 73 | - ec2:DescribeImages 74 | Resource: '*' 75 | CustomResource: 76 | Type: Custom::CustomResource 77 | Properties: 78 | ServiceToken: !GetAtt 'CustomFunction.Arn' 79 | ParameterOne: Parameter to pass into Custom Lambda Function 80 | Outputs: 81 | Message: 82 | Description: The message from the custom resource. 83 | Value: !GetAtt 'CustomResource.Message' 84 | CustomFunctionArn: 85 | Description: The arn of the custom resource function. 86 | Value: !GetAtt 'CustomFunction.Arn' 87 | -------------------------------------------------------------------------------- /cfn/yml/create-custom-resource.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: AWS CloudFormation to set up a custom CloudFormation resource with Lambda. 3 | Parameters: 4 | LambdaRuntime: 5 | Description: The Lambda runtime to use 6 | Type: String 7 | AllowedValues: 8 | - nodejs 9 | - nodejs4.3 10 | - nodejs6.10 11 | - nodejs8.10 12 | - java8 13 | - python2.7 14 | - python3.6 15 | - dotnetcore1.0 16 | - dotnetcore2.0 17 | - dotnetcore2.1 18 | - nodejs4.3-edge 19 | - go1.x 20 | ModuleName: 21 | Description: The name of the JavaScript file 22 | Type: String 23 | Default: customresource 24 | HandlerName: 25 | Description: The name of the lambda handler 26 | Type: String 27 | Default: handler 28 | S3Bucket: 29 | Description: The name of the bucket that contains your packaged source 30 | Type: String 31 | S3Key: 32 | Description: The name of the ZIP package 33 | Type: String 34 | Default: custom-resource.zip 35 | Resources: 36 | CustomFunction: 37 | Type: AWS::Lambda::Function 38 | Properties: 39 | Code: 40 | S3Bucket: !Ref 'S3Bucket' 41 | S3Key: !Ref 'S3Key' 42 | Handler: !Join ['', [!Ref 'ModuleName', ., !Ref 'HandlerName']] 43 | Role: !GetAtt 'LambdaExecutionRole.Arn' 44 | Runtime: !Ref 'LambdaRuntime' 45 | Timeout: '30' 46 | LambdaExecutionRole: 47 | Type: AWS::IAM::Role 48 | Properties: 49 | AssumeRolePolicyDocument: 50 | Version: '2012-10-17' 51 | Statement: 52 | - Effect: Allow 53 | Principal: 54 | Service: 55 | - lambda.amazonaws.com 56 | Action: 57 | - sts:AssumeRole 58 | Path: / 59 | Policies: 60 | - PolicyName: root 61 | PolicyDocument: 62 | Version: '2012-10-17' 63 | Statement: 64 | - Effect: Allow 65 | Action: 66 | - logs:CreateLogGroup 67 | - logs:CreateLogStream 68 | - logs:PutLogEvents 69 | Resource: arn:aws:logs:*:*:* 70 | - Effect: Allow 71 | Action: 72 | - ec2:DescribeImages 73 | Resource: '*' 74 | Outputs: 75 | CustomFunctionArn: 76 | Description: The arn of the custom resource function. 77 | Value: !GetAtt 'CustomFunction.Arn' 78 | -------------------------------------------------------------------------------- /cfn/yml/use-custom-resource.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: AWS CloudFormation to consume a custom CloudFormation resource with Lambda. 3 | It calls a previously created CloudFormation Custom Resource Lambda and puts the 4 | result into the output of the stack. 5 | Parameters: 6 | CustomFunctionArn: 7 | Type: String 8 | Description: the ARN of the custom resource (this is an output of the previous 9 | CloudFormation stack 10 | Resources: 11 | CustomResource: 12 | Type: Custom::CustomResource 13 | Properties: 14 | ServiceToken: !Ref 'CustomFunctionArn' 15 | ParameterOne: Parameter to pass into Custom Lambda Function 16 | Outputs: 17 | Message: 18 | Description: The message from the custom resource. 19 | Value: !GetAtt 'CustomResource.Message' 20 | -------------------------------------------------------------------------------- /lambda/java/README.md: -------------------------------------------------------------------------------- 1 | AWS Lambda java8 CloudFormation custom resource example 2 | ======================================================= 3 | 4 | How to create and package java lambda function 5 | ---------------------------------------------- 6 | 7 | 1. git clone git@github.com:stelligent/cloudformation-custom-resources.git 8 | 2. cd cloudformation-custom-resources/lambda/java 9 | 3. ./gradlew buildZip 10 | 4. zip package will be created in build/distributions/java.zip 11 | 5. Upload this to S3 bucket. Remember to pass this bucket name in as ParameterValue for ParameterKey="S3Bucket" 12 | 13 | Create cfn custom resource with java specific sample params 14 | ----------------------------------------------------------- 15 | 16 | aws cloudformation create-stack \ 17 | --stack-name test-create-custom-resource-cfn-20171120154514\ 18 | --template-body file://cfn/json/create-custom-resource.json\ 19 | --capabilities CAPABILITY_IAM\ 20 | --disable-rollback\ 21 | --parameters\ 22 | ParameterKey="S3Bucket",ParameterValue="$value-of-s3-bucket-name"\ 23 | ParameterKey="S3Key",ParameterValue="customresource.jar"\ 24 | ParameterKey="ModuleName",ParameterValue="com.stelligent.customresource"\ 25 | ParameterKey="HandlerName",ParameterValue="CustomResourceHandler"\ 26 | ParameterKey="LambdaRuntime",ParameterValue="java8" 27 | 28 | Use cfn custom resource with java specific sample params 29 | ------------------- 30 | 31 | aws cloudformation create-stack \ 32 | --stack-name test-use-custom-resource-cfn-20171120153114\ 33 | --template-body file://cfn/json/use-custom-resource.json \ 34 | --disable-rollback \ 35 | --parameters \ 36 | ParameterKey="CustomFunctionArn",\ 37 | ParameterValue="$value-of-lambda-created-by-create-cfn-run" 38 | -------------------------------------------------------------------------------- /lambda/java/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | repositories { 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | compile ( 9 | 'com.amazonaws:aws-lambda-java-core:1.1.0', 10 | 'com.amazonaws:aws-lambda-java-events:1.3.0', 11 | 'com.amazonaws:aws-java-sdk-bom:1.11.232', 12 | 'junit:junit:4.12', 13 | 'org.json:json:20171018' 14 | ) 15 | } 16 | 17 | task buildZip(type: Zip) { 18 | from compileJava 19 | from processResources 20 | into('lib') { 21 | from configurations.runtime 22 | } 23 | } 24 | 25 | task buildDocker(type: Copy) { 26 | from compileJava 27 | from processResources 28 | into('lib') { 29 | from configurations.runtime 30 | } 31 | into 'build/docker' 32 | } 33 | 34 | build.dependsOn buildDocker 35 | -------------------------------------------------------------------------------- /lambda/java/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stelligent/cloudformation-custom-resources/92b7d16b92fe2779cc7c239d7f2acc973a523bf4/lambda/java/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /lambda/java/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Aug 03 10:40:54 EDT 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.0-bin.zip 7 | -------------------------------------------------------------------------------- /lambda/java/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 165 | if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then 166 | cd "$(dirname "$0")" 167 | fi 168 | 169 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 170 | -------------------------------------------------------------------------------- /lambda/java/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /lambda/java/src/main/java/com/stelligent/customresource/CustomResourceHandler.java: -------------------------------------------------------------------------------- 1 | package com.stelligent.customresource; 2 | 3 | import com.amazonaws.services.lambda.runtime.Context; 4 | import com.amazonaws.services.lambda.runtime.LambdaLogger; 5 | import com.amazonaws.services.lambda.runtime.RequestHandler; 6 | import java.io.IOException; 7 | import java.io.OutputStreamWriter; 8 | import java.net.HttpURLConnection; 9 | import java.net.URL; 10 | import java.util.Map; 11 | import java.util.concurrent.ExecutionException; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.Future; 15 | import java.util.concurrent.TimeUnit; 16 | import java.util.concurrent.TimeoutException; 17 | import org.json.JSONObject; 18 | 19 | public class CustomResourceHandler implements RequestHandler, Object> { 20 | 21 | @Override 22 | public Object handleRequest(Map input, Context context) { 23 | LambdaLogger logger = context.getLogger(); 24 | logger.log("Input: " + input); 25 | 26 | final String requestType = (String) input.get("RequestType"); 27 | 28 | ExecutorService service = Executors.newSingleThreadExecutor(); 29 | JSONObject responseData = new JSONObject(); 30 | try { 31 | if (requestType == null) { 32 | throw new RuntimeException(); 33 | } 34 | 35 | Runnable r = new Runnable() { 36 | @Override 37 | public void run() { 38 | try { 39 | Thread.sleep(10000); 40 | } catch (final InterruptedException e) { 41 | // empty block 42 | } 43 | if (requestType.equalsIgnoreCase("Create")) { 44 | logger.log("CREATE!"); 45 | // Put your custom create logic here 46 | responseData.put("Message", "Resource creation successful!"); 47 | sendResponse(input, context, "SUCCESS", responseData); 48 | } else if (requestType.equalsIgnoreCase("Update")) { 49 | logger.log("UDPATE!"); 50 | // Put your custom update logic here 51 | responseData.put("Message", "Resource update successful!"); 52 | sendResponse(input, context, "SUCCESS", responseData); 53 | } else if (requestType.equalsIgnoreCase("Delete")) { 54 | logger.log("DELETE!"); 55 | // Put your custom delete logic here 56 | responseData.put("Message", "Resource deletion successful!"); 57 | sendResponse(input, context, "SUCCESS", responseData); 58 | } else { 59 | logger.log("FAILURE!"); 60 | sendResponse(input, context, "FAILED", responseData); 61 | } 62 | } 63 | }; 64 | Future f = service.submit(r); 65 | f.get(context.getRemainingTimeInMillis() - 1000, TimeUnit.MILLISECONDS); 66 | } catch (final TimeoutException | InterruptedException 67 | | ExecutionException e) { 68 | logger.log("FAILURE!"); 69 | sendResponse(input, context, "FAILED", responseData); 70 | // Took too long! 71 | } finally { 72 | service.shutdown(); 73 | } 74 | return null; 75 | } 76 | 77 | /** Send a response to CloudFormation regarding progress in creating resource. */ 78 | public final Object sendResponse( 79 | final Map input, 80 | final Context context, 81 | final String responseStatus, 82 | JSONObject responseData) { 83 | 84 | String responseUrl = (String) input.get("ResponseURL"); 85 | context.getLogger().log("ResponseURL: " + responseUrl); 86 | 87 | URL url; 88 | try { 89 | url = new URL(responseUrl); 90 | HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 91 | connection.setDoOutput(true); 92 | connection.setRequestMethod("PUT"); 93 | 94 | JSONObject responseBody = new JSONObject(); 95 | responseBody.put("Status", responseStatus); 96 | responseBody.put("PhysicalResourceId", context.getLogStreamName()); 97 | responseBody.put("StackId", input.get("StackId")); 98 | responseBody.put("RequestId", input.get("RequestId")); 99 | responseBody.put("LogicalResourceId", input.get("LogicalResourceId")); 100 | responseBody.put("Data", responseData); 101 | 102 | OutputStreamWriter response = new OutputStreamWriter(connection.getOutputStream()); 103 | response.write(responseBody.toString()); 104 | response.close(); 105 | context.getLogger().log("Response Code: " + connection.getResponseCode()); 106 | 107 | } catch (IOException e) { 108 | e.printStackTrace(); 109 | } 110 | 111 | return null; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /lambda/nodejs/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: standard 2 | -------------------------------------------------------------------------------- /lambda/nodejs/customresource.js: -------------------------------------------------------------------------------- 1 | exports.handler = function (event, context, callback) { 2 | // Install watchdog timer as the first thing 3 | setupWatchdogTimer(event, context, callback) 4 | console.log('REQUEST RECEIVED:\n' + JSON.stringify(event)) 5 | if (event.RequestType === 'Create') { 6 | console.log('CREATE!') 7 | // Put your custom create logic here 8 | sendResponse(event, context, 'SUCCESS', { 'Message': 'Resource creation successful!' }) 9 | } else if (event.RequestType === 'Update') { 10 | console.log('UDPATE!') 11 | // Put your custom update logic here 12 | sendResponse(event, context, 'SUCCESS', { 'Message': 'Resource update successful!' }) 13 | } else if (event.RequestType === 'Delete') { 14 | console.log('DELETE!') 15 | // Put your custom delete logic here 16 | sendResponse(event, context, 'SUCCESS', { 'Message': 'Resource deletion successful!' }) 17 | } else { 18 | console.log('FAILED!') 19 | sendResponse(event, context, 'FAILED') 20 | } 21 | } 22 | 23 | function setupWatchdogTimer (event, context, callback) { 24 | const timeoutHandler = () => { 25 | console.log('Timeout FAILURE!') 26 | // Emit event to 'sendResponse', then callback with an error from this 27 | // function 28 | new Promise(() => sendResponse(event, context, 'FAILED')) 29 | .then(() => callback(new Error('Function timed out'))) 30 | } 31 | 32 | // Set timer so it triggers one second before this function would timeout 33 | setTimeout(timeoutHandler, context.getRemainingTimeInMillis() - 1000) 34 | } 35 | 36 | // Send response to the pre-signed S3 URL 37 | function sendResponse (event, context, responseStatus, responseData) { 38 | console.log('Sending response ' + responseStatus) 39 | var responseBody = JSON.stringify({ 40 | Status: responseStatus, 41 | Reason: 'See the details in CloudWatch Log Stream: ' + context.logStreamName, 42 | PhysicalResourceId: context.logStreamName, 43 | StackId: event.StackId, 44 | RequestId: event.RequestId, 45 | LogicalResourceId: event.LogicalResourceId, 46 | Data: responseData 47 | }) 48 | 49 | console.log('RESPONSE BODY:\n', responseBody) 50 | 51 | var https = require('https') 52 | var url = require('url') 53 | 54 | var parsedUrl = url.parse(event.ResponseURL) 55 | var options = { 56 | hostname: parsedUrl.hostname, 57 | port: 443, 58 | path: parsedUrl.path, 59 | method: 'PUT', 60 | headers: { 61 | 'content-type': '', 62 | 'content-length': responseBody.length 63 | } 64 | } 65 | 66 | console.log('SENDING RESPONSE...\n') 67 | 68 | var request = https.request(options, function (response) { 69 | console.log('STATUS: ' + response.statusCode) 70 | console.log('HEADERS: ' + JSON.stringify(response.headers)) 71 | // Tell AWS Lambda that the function execution is done 72 | context.done() 73 | }) 74 | 75 | request.on('error', function (error) { 76 | console.log('sendResponse Error:' + error) 77 | // Tell AWS Lambda that the function execution is done 78 | context.done() 79 | }) 80 | 81 | // write data to request body 82 | request.write(responseBody) 83 | request.end() 84 | } 85 | -------------------------------------------------------------------------------- /lambda/nodejs/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "customresource", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.0.0", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", 10 | "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "^7.0.0" 14 | } 15 | }, 16 | "@babel/highlight": { 17 | "version": "7.0.0", 18 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", 19 | "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", 20 | "dev": true, 21 | "requires": { 22 | "chalk": "^2.0.0", 23 | "esutils": "^2.0.2", 24 | "js-tokens": "^4.0.0" 25 | } 26 | }, 27 | "acorn": { 28 | "version": "6.4.1", 29 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", 30 | "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", 31 | "dev": true 32 | }, 33 | "acorn-jsx": { 34 | "version": "5.0.1", 35 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", 36 | "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", 37 | "dev": true 38 | }, 39 | "ajv": { 40 | "version": "6.10.0", 41 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", 42 | "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", 43 | "dev": true, 44 | "requires": { 45 | "fast-deep-equal": "^2.0.1", 46 | "fast-json-stable-stringify": "^2.0.0", 47 | "json-schema-traverse": "^0.4.1", 48 | "uri-js": "^4.2.2" 49 | } 50 | }, 51 | "ansi-escapes": { 52 | "version": "3.2.0", 53 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", 54 | "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", 55 | "dev": true 56 | }, 57 | "ansi-regex": { 58 | "version": "3.0.0", 59 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 60 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 61 | "dev": true 62 | }, 63 | "ansi-styles": { 64 | "version": "3.2.1", 65 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 66 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 67 | "dev": true, 68 | "requires": { 69 | "color-convert": "^1.9.0" 70 | } 71 | }, 72 | "argparse": { 73 | "version": "1.0.10", 74 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 75 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 76 | "dev": true, 77 | "requires": { 78 | "sprintf-js": "~1.0.2" 79 | } 80 | }, 81 | "astral-regex": { 82 | "version": "1.0.0", 83 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", 84 | "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", 85 | "dev": true 86 | }, 87 | "balanced-match": { 88 | "version": "1.0.0", 89 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 90 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 91 | "dev": true 92 | }, 93 | "brace-expansion": { 94 | "version": "1.1.11", 95 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 96 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 97 | "dev": true, 98 | "requires": { 99 | "balanced-match": "^1.0.0", 100 | "concat-map": "0.0.1" 101 | } 102 | }, 103 | "callsites": { 104 | "version": "3.1.0", 105 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 106 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 107 | "dev": true 108 | }, 109 | "chalk": { 110 | "version": "2.4.2", 111 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 112 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 113 | "dev": true, 114 | "requires": { 115 | "ansi-styles": "^3.2.1", 116 | "escape-string-regexp": "^1.0.5", 117 | "supports-color": "^5.3.0" 118 | } 119 | }, 120 | "chardet": { 121 | "version": "0.7.0", 122 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 123 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", 124 | "dev": true 125 | }, 126 | "cli-cursor": { 127 | "version": "2.1.0", 128 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", 129 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", 130 | "dev": true, 131 | "requires": { 132 | "restore-cursor": "^2.0.0" 133 | } 134 | }, 135 | "cli-width": { 136 | "version": "2.2.0", 137 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 138 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 139 | "dev": true 140 | }, 141 | "color-convert": { 142 | "version": "1.9.3", 143 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 144 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 145 | "dev": true, 146 | "requires": { 147 | "color-name": "1.1.3" 148 | } 149 | }, 150 | "color-name": { 151 | "version": "1.1.3", 152 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 153 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 154 | "dev": true 155 | }, 156 | "concat-map": { 157 | "version": "0.0.1", 158 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 159 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 160 | "dev": true 161 | }, 162 | "contains-path": { 163 | "version": "0.1.0", 164 | "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", 165 | "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", 166 | "dev": true 167 | }, 168 | "cross-spawn": { 169 | "version": "6.0.5", 170 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 171 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 172 | "dev": true, 173 | "requires": { 174 | "nice-try": "^1.0.4", 175 | "path-key": "^2.0.1", 176 | "semver": "^5.5.0", 177 | "shebang-command": "^1.2.0", 178 | "which": "^1.2.9" 179 | } 180 | }, 181 | "debug": { 182 | "version": "4.1.1", 183 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 184 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 185 | "dev": true, 186 | "requires": { 187 | "ms": "^2.1.1" 188 | } 189 | }, 190 | "deep-is": { 191 | "version": "0.1.3", 192 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 193 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 194 | "dev": true 195 | }, 196 | "doctrine": { 197 | "version": "3.0.0", 198 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 199 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 200 | "dev": true, 201 | "requires": { 202 | "esutils": "^2.0.2" 203 | } 204 | }, 205 | "emoji-regex": { 206 | "version": "7.0.3", 207 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", 208 | "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 209 | "dev": true 210 | }, 211 | "error-ex": { 212 | "version": "1.3.2", 213 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 214 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 215 | "dev": true, 216 | "requires": { 217 | "is-arrayish": "^0.2.1" 218 | } 219 | }, 220 | "escape-string-regexp": { 221 | "version": "1.0.5", 222 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 223 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 224 | "dev": true 225 | }, 226 | "eslint": { 227 | "version": "5.16.0", 228 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", 229 | "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", 230 | "dev": true, 231 | "requires": { 232 | "@babel/code-frame": "^7.0.0", 233 | "ajv": "^6.9.1", 234 | "chalk": "^2.1.0", 235 | "cross-spawn": "^6.0.5", 236 | "debug": "^4.0.1", 237 | "doctrine": "^3.0.0", 238 | "eslint-scope": "^4.0.3", 239 | "eslint-utils": "^1.3.1", 240 | "eslint-visitor-keys": "^1.0.0", 241 | "espree": "^5.0.1", 242 | "esquery": "^1.0.1", 243 | "esutils": "^2.0.2", 244 | "file-entry-cache": "^5.0.1", 245 | "functional-red-black-tree": "^1.0.1", 246 | "glob": "^7.1.2", 247 | "globals": "^11.7.0", 248 | "ignore": "^4.0.6", 249 | "import-fresh": "^3.0.0", 250 | "imurmurhash": "^0.1.4", 251 | "inquirer": "^6.2.2", 252 | "js-yaml": "^3.13.0", 253 | "json-stable-stringify-without-jsonify": "^1.0.1", 254 | "levn": "^0.3.0", 255 | "lodash": "^4.17.11", 256 | "minimatch": "^3.0.4", 257 | "mkdirp": "^0.5.1", 258 | "natural-compare": "^1.4.0", 259 | "optionator": "^0.8.2", 260 | "path-is-inside": "^1.0.2", 261 | "progress": "^2.0.0", 262 | "regexpp": "^2.0.1", 263 | "semver": "^5.5.1", 264 | "strip-ansi": "^4.0.0", 265 | "strip-json-comments": "^2.0.1", 266 | "table": "^5.2.3", 267 | "text-table": "^0.2.0" 268 | } 269 | }, 270 | "eslint-config-standard": { 271 | "version": "11.0.0", 272 | "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz", 273 | "integrity": "sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw==", 274 | "dev": true 275 | }, 276 | "eslint-import-resolver-node": { 277 | "version": "0.3.2", 278 | "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", 279 | "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", 280 | "dev": true, 281 | "requires": { 282 | "debug": "^2.6.9", 283 | "resolve": "^1.5.0" 284 | }, 285 | "dependencies": { 286 | "debug": { 287 | "version": "2.6.9", 288 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 289 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 290 | "dev": true, 291 | "requires": { 292 | "ms": "2.0.0" 293 | } 294 | }, 295 | "ms": { 296 | "version": "2.0.0", 297 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 298 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 299 | "dev": true 300 | } 301 | } 302 | }, 303 | "eslint-module-utils": { 304 | "version": "2.3.0", 305 | "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.3.0.tgz", 306 | "integrity": "sha512-lmDJgeOOjk8hObTysjqH7wyMi+nsHwwvfBykwfhjR1LNdd7C2uFJBvx4OpWYpXOw4df1yE1cDEVd1yLHitk34w==", 307 | "dev": true, 308 | "requires": { 309 | "debug": "^2.6.8", 310 | "pkg-dir": "^2.0.0" 311 | }, 312 | "dependencies": { 313 | "debug": { 314 | "version": "2.6.9", 315 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 316 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 317 | "dev": true, 318 | "requires": { 319 | "ms": "2.0.0" 320 | } 321 | }, 322 | "ms": { 323 | "version": "2.0.0", 324 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 325 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 326 | "dev": true 327 | } 328 | } 329 | }, 330 | "eslint-plugin-es": { 331 | "version": "1.4.0", 332 | "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz", 333 | "integrity": "sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw==", 334 | "dev": true, 335 | "requires": { 336 | "eslint-utils": "^1.3.0", 337 | "regexpp": "^2.0.1" 338 | } 339 | }, 340 | "eslint-plugin-import": { 341 | "version": "2.16.0", 342 | "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.16.0.tgz", 343 | "integrity": "sha512-z6oqWlf1x5GkHIFgrSvtmudnqM6Q60KM4KvpWi5ubonMjycLjndvd5+8VAZIsTlHC03djdgJuyKG6XO577px6A==", 344 | "dev": true, 345 | "requires": { 346 | "contains-path": "^0.1.0", 347 | "debug": "^2.6.9", 348 | "doctrine": "1.5.0", 349 | "eslint-import-resolver-node": "^0.3.2", 350 | "eslint-module-utils": "^2.3.0", 351 | "has": "^1.0.3", 352 | "lodash": "^4.17.11", 353 | "minimatch": "^3.0.4", 354 | "read-pkg-up": "^2.0.0", 355 | "resolve": "^1.9.0" 356 | }, 357 | "dependencies": { 358 | "debug": { 359 | "version": "2.6.9", 360 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 361 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 362 | "dev": true, 363 | "requires": { 364 | "ms": "2.0.0" 365 | } 366 | }, 367 | "doctrine": { 368 | "version": "1.5.0", 369 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", 370 | "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", 371 | "dev": true, 372 | "requires": { 373 | "esutils": "^2.0.2", 374 | "isarray": "^1.0.0" 375 | } 376 | }, 377 | "ms": { 378 | "version": "2.0.0", 379 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 380 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 381 | "dev": true 382 | } 383 | } 384 | }, 385 | "eslint-plugin-node": { 386 | "version": "7.0.1", 387 | "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz", 388 | "integrity": "sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw==", 389 | "dev": true, 390 | "requires": { 391 | "eslint-plugin-es": "^1.3.1", 392 | "eslint-utils": "^1.3.1", 393 | "ignore": "^4.0.2", 394 | "minimatch": "^3.0.4", 395 | "resolve": "^1.8.1", 396 | "semver": "^5.5.0" 397 | } 398 | }, 399 | "eslint-plugin-promise": { 400 | "version": "3.8.0", 401 | "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz", 402 | "integrity": "sha512-JiFL9UFR15NKpHyGii1ZcvmtIqa3UTwiDAGb8atSffe43qJ3+1czVGN6UtkklpcJ2DVnqvTMzEKRaJdBkAL2aQ==", 403 | "dev": true 404 | }, 405 | "eslint-plugin-standard": { 406 | "version": "3.1.0", 407 | "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.1.0.tgz", 408 | "integrity": "sha512-fVcdyuKRr0EZ4fjWl3c+gp1BANFJD1+RaWa2UPYfMZ6jCtp5RG00kSaXnK/dE5sYzt4kaWJ9qdxqUfc0d9kX0w==", 409 | "dev": true 410 | }, 411 | "eslint-scope": { 412 | "version": "4.0.3", 413 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", 414 | "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", 415 | "dev": true, 416 | "requires": { 417 | "esrecurse": "^4.1.0", 418 | "estraverse": "^4.1.1" 419 | } 420 | }, 421 | "eslint-utils": { 422 | "version": "1.4.2", 423 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", 424 | "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", 425 | "dev": true, 426 | "requires": { 427 | "eslint-visitor-keys": "^1.0.0" 428 | } 429 | }, 430 | "eslint-visitor-keys": { 431 | "version": "1.0.0", 432 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", 433 | "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", 434 | "dev": true 435 | }, 436 | "espree": { 437 | "version": "5.0.1", 438 | "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", 439 | "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", 440 | "dev": true, 441 | "requires": { 442 | "acorn": "^6.0.7", 443 | "acorn-jsx": "^5.0.0", 444 | "eslint-visitor-keys": "^1.0.0" 445 | } 446 | }, 447 | "esprima": { 448 | "version": "4.0.1", 449 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 450 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 451 | "dev": true 452 | }, 453 | "esquery": { 454 | "version": "1.0.1", 455 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", 456 | "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", 457 | "dev": true, 458 | "requires": { 459 | "estraverse": "^4.0.0" 460 | } 461 | }, 462 | "esrecurse": { 463 | "version": "4.2.1", 464 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", 465 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", 466 | "dev": true, 467 | "requires": { 468 | "estraverse": "^4.1.0" 469 | } 470 | }, 471 | "estraverse": { 472 | "version": "4.2.0", 473 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 474 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 475 | "dev": true 476 | }, 477 | "esutils": { 478 | "version": "2.0.2", 479 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 480 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 481 | "dev": true 482 | }, 483 | "external-editor": { 484 | "version": "3.0.3", 485 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", 486 | "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", 487 | "dev": true, 488 | "requires": { 489 | "chardet": "^0.7.0", 490 | "iconv-lite": "^0.4.24", 491 | "tmp": "^0.0.33" 492 | } 493 | }, 494 | "fast-deep-equal": { 495 | "version": "2.0.1", 496 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 497 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", 498 | "dev": true 499 | }, 500 | "fast-json-stable-stringify": { 501 | "version": "2.0.0", 502 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 503 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", 504 | "dev": true 505 | }, 506 | "fast-levenshtein": { 507 | "version": "2.0.6", 508 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 509 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 510 | "dev": true 511 | }, 512 | "figures": { 513 | "version": "2.0.0", 514 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", 515 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", 516 | "dev": true, 517 | "requires": { 518 | "escape-string-regexp": "^1.0.5" 519 | } 520 | }, 521 | "file-entry-cache": { 522 | "version": "5.0.1", 523 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", 524 | "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", 525 | "dev": true, 526 | "requires": { 527 | "flat-cache": "^2.0.1" 528 | } 529 | }, 530 | "find-up": { 531 | "version": "2.1.0", 532 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 533 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 534 | "dev": true, 535 | "requires": { 536 | "locate-path": "^2.0.0" 537 | } 538 | }, 539 | "flat-cache": { 540 | "version": "2.0.1", 541 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", 542 | "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", 543 | "dev": true, 544 | "requires": { 545 | "flatted": "^2.0.0", 546 | "rimraf": "2.6.3", 547 | "write": "1.0.3" 548 | } 549 | }, 550 | "flatted": { 551 | "version": "2.0.0", 552 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", 553 | "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", 554 | "dev": true 555 | }, 556 | "fs.realpath": { 557 | "version": "1.0.0", 558 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 559 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 560 | "dev": true 561 | }, 562 | "function-bind": { 563 | "version": "1.1.1", 564 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 565 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 566 | "dev": true 567 | }, 568 | "functional-red-black-tree": { 569 | "version": "1.0.1", 570 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", 571 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", 572 | "dev": true 573 | }, 574 | "glob": { 575 | "version": "7.1.3", 576 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 577 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 578 | "dev": true, 579 | "requires": { 580 | "fs.realpath": "^1.0.0", 581 | "inflight": "^1.0.4", 582 | "inherits": "2", 583 | "minimatch": "^3.0.4", 584 | "once": "^1.3.0", 585 | "path-is-absolute": "^1.0.0" 586 | } 587 | }, 588 | "globals": { 589 | "version": "11.11.0", 590 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", 591 | "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", 592 | "dev": true 593 | }, 594 | "graceful-fs": { 595 | "version": "4.1.15", 596 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", 597 | "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", 598 | "dev": true 599 | }, 600 | "has": { 601 | "version": "1.0.3", 602 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 603 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 604 | "dev": true, 605 | "requires": { 606 | "function-bind": "^1.1.1" 607 | } 608 | }, 609 | "has-flag": { 610 | "version": "3.0.0", 611 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 612 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 613 | "dev": true 614 | }, 615 | "hosted-git-info": { 616 | "version": "2.7.1", 617 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", 618 | "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", 619 | "dev": true 620 | }, 621 | "iconv-lite": { 622 | "version": "0.4.24", 623 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 624 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 625 | "dev": true, 626 | "requires": { 627 | "safer-buffer": ">= 2.1.2 < 3" 628 | } 629 | }, 630 | "ignore": { 631 | "version": "4.0.6", 632 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", 633 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", 634 | "dev": true 635 | }, 636 | "import-fresh": { 637 | "version": "3.0.0", 638 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", 639 | "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", 640 | "dev": true, 641 | "requires": { 642 | "parent-module": "^1.0.0", 643 | "resolve-from": "^4.0.0" 644 | } 645 | }, 646 | "imurmurhash": { 647 | "version": "0.1.4", 648 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 649 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 650 | "dev": true 651 | }, 652 | "inflight": { 653 | "version": "1.0.6", 654 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 655 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 656 | "dev": true, 657 | "requires": { 658 | "once": "^1.3.0", 659 | "wrappy": "1" 660 | } 661 | }, 662 | "inherits": { 663 | "version": "2.0.3", 664 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 665 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 666 | "dev": true 667 | }, 668 | "inquirer": { 669 | "version": "6.2.2", 670 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", 671 | "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", 672 | "dev": true, 673 | "requires": { 674 | "ansi-escapes": "^3.2.0", 675 | "chalk": "^2.4.2", 676 | "cli-cursor": "^2.1.0", 677 | "cli-width": "^2.0.0", 678 | "external-editor": "^3.0.3", 679 | "figures": "^2.0.0", 680 | "lodash": "^4.17.11", 681 | "mute-stream": "0.0.7", 682 | "run-async": "^2.2.0", 683 | "rxjs": "^6.4.0", 684 | "string-width": "^2.1.0", 685 | "strip-ansi": "^5.0.0", 686 | "through": "^2.3.6" 687 | }, 688 | "dependencies": { 689 | "ansi-regex": { 690 | "version": "4.1.0", 691 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 692 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 693 | "dev": true 694 | }, 695 | "strip-ansi": { 696 | "version": "5.2.0", 697 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 698 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 699 | "dev": true, 700 | "requires": { 701 | "ansi-regex": "^4.1.0" 702 | } 703 | } 704 | } 705 | }, 706 | "is-arrayish": { 707 | "version": "0.2.1", 708 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 709 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 710 | "dev": true 711 | }, 712 | "is-fullwidth-code-point": { 713 | "version": "2.0.0", 714 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 715 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 716 | "dev": true 717 | }, 718 | "is-promise": { 719 | "version": "2.1.0", 720 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", 721 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", 722 | "dev": true 723 | }, 724 | "isarray": { 725 | "version": "1.0.0", 726 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 727 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 728 | "dev": true 729 | }, 730 | "isexe": { 731 | "version": "2.0.0", 732 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 733 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 734 | "dev": true 735 | }, 736 | "js-tokens": { 737 | "version": "4.0.0", 738 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 739 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 740 | "dev": true 741 | }, 742 | "js-yaml": { 743 | "version": "3.13.1", 744 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", 745 | "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", 746 | "dev": true, 747 | "requires": { 748 | "argparse": "^1.0.7", 749 | "esprima": "^4.0.0" 750 | } 751 | }, 752 | "json-schema-traverse": { 753 | "version": "0.4.1", 754 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 755 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 756 | "dev": true 757 | }, 758 | "json-stable-stringify-without-jsonify": { 759 | "version": "1.0.1", 760 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 761 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", 762 | "dev": true 763 | }, 764 | "levn": { 765 | "version": "0.3.0", 766 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 767 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 768 | "dev": true, 769 | "requires": { 770 | "prelude-ls": "~1.1.2", 771 | "type-check": "~0.3.2" 772 | } 773 | }, 774 | "load-json-file": { 775 | "version": "2.0.0", 776 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", 777 | "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", 778 | "dev": true, 779 | "requires": { 780 | "graceful-fs": "^4.1.2", 781 | "parse-json": "^2.2.0", 782 | "pify": "^2.0.0", 783 | "strip-bom": "^3.0.0" 784 | } 785 | }, 786 | "locate-path": { 787 | "version": "2.0.0", 788 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 789 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 790 | "dev": true, 791 | "requires": { 792 | "p-locate": "^2.0.0", 793 | "path-exists": "^3.0.0" 794 | } 795 | }, 796 | "lodash": { 797 | "version": "4.17.21", 798 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 799 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 800 | "dev": true 801 | }, 802 | "mimic-fn": { 803 | "version": "1.2.0", 804 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 805 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", 806 | "dev": true 807 | }, 808 | "minimatch": { 809 | "version": "3.0.4", 810 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 811 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 812 | "dev": true, 813 | "requires": { 814 | "brace-expansion": "^1.1.7" 815 | } 816 | }, 817 | "minimist": { 818 | "version": "1.2.5", 819 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 820 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", 821 | "dev": true 822 | }, 823 | "mkdirp": { 824 | "version": "0.5.5", 825 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", 826 | "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", 827 | "dev": true, 828 | "requires": { 829 | "minimist": "^1.2.5" 830 | } 831 | }, 832 | "ms": { 833 | "version": "2.1.1", 834 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 835 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 836 | "dev": true 837 | }, 838 | "mute-stream": { 839 | "version": "0.0.7", 840 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", 841 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", 842 | "dev": true 843 | }, 844 | "natural-compare": { 845 | "version": "1.4.0", 846 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 847 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 848 | "dev": true 849 | }, 850 | "nice-try": { 851 | "version": "1.0.5", 852 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 853 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", 854 | "dev": true 855 | }, 856 | "normalize-package-data": { 857 | "version": "2.5.0", 858 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", 859 | "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", 860 | "dev": true, 861 | "requires": { 862 | "hosted-git-info": "^2.1.4", 863 | "resolve": "^1.10.0", 864 | "semver": "2 || 3 || 4 || 5", 865 | "validate-npm-package-license": "^3.0.1" 866 | } 867 | }, 868 | "once": { 869 | "version": "1.4.0", 870 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 871 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 872 | "dev": true, 873 | "requires": { 874 | "wrappy": "1" 875 | } 876 | }, 877 | "onetime": { 878 | "version": "2.0.1", 879 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", 880 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", 881 | "dev": true, 882 | "requires": { 883 | "mimic-fn": "^1.0.0" 884 | } 885 | }, 886 | "optionator": { 887 | "version": "0.8.2", 888 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 889 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 890 | "dev": true, 891 | "requires": { 892 | "deep-is": "~0.1.3", 893 | "fast-levenshtein": "~2.0.4", 894 | "levn": "~0.3.0", 895 | "prelude-ls": "~1.1.2", 896 | "type-check": "~0.3.2", 897 | "wordwrap": "~1.0.0" 898 | } 899 | }, 900 | "os-tmpdir": { 901 | "version": "1.0.2", 902 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 903 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 904 | "dev": true 905 | }, 906 | "p-limit": { 907 | "version": "1.3.0", 908 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", 909 | "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", 910 | "dev": true, 911 | "requires": { 912 | "p-try": "^1.0.0" 913 | } 914 | }, 915 | "p-locate": { 916 | "version": "2.0.0", 917 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 918 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 919 | "dev": true, 920 | "requires": { 921 | "p-limit": "^1.1.0" 922 | } 923 | }, 924 | "p-try": { 925 | "version": "1.0.0", 926 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 927 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", 928 | "dev": true 929 | }, 930 | "parent-module": { 931 | "version": "1.0.1", 932 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 933 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 934 | "dev": true, 935 | "requires": { 936 | "callsites": "^3.0.0" 937 | } 938 | }, 939 | "parse-json": { 940 | "version": "2.2.0", 941 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 942 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 943 | "dev": true, 944 | "requires": { 945 | "error-ex": "^1.2.0" 946 | } 947 | }, 948 | "path-exists": { 949 | "version": "3.0.0", 950 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 951 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 952 | "dev": true 953 | }, 954 | "path-is-absolute": { 955 | "version": "1.0.1", 956 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 957 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 958 | "dev": true 959 | }, 960 | "path-is-inside": { 961 | "version": "1.0.2", 962 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 963 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 964 | "dev": true 965 | }, 966 | "path-key": { 967 | "version": "2.0.1", 968 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 969 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 970 | "dev": true 971 | }, 972 | "path-parse": { 973 | "version": "1.0.6", 974 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 975 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 976 | "dev": true 977 | }, 978 | "path-type": { 979 | "version": "2.0.0", 980 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", 981 | "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", 982 | "dev": true, 983 | "requires": { 984 | "pify": "^2.0.0" 985 | } 986 | }, 987 | "pify": { 988 | "version": "2.3.0", 989 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 990 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 991 | "dev": true 992 | }, 993 | "pkg-dir": { 994 | "version": "2.0.0", 995 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", 996 | "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", 997 | "dev": true, 998 | "requires": { 999 | "find-up": "^2.1.0" 1000 | } 1001 | }, 1002 | "prelude-ls": { 1003 | "version": "1.1.2", 1004 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1005 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1006 | "dev": true 1007 | }, 1008 | "progress": { 1009 | "version": "2.0.3", 1010 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", 1011 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", 1012 | "dev": true 1013 | }, 1014 | "punycode": { 1015 | "version": "2.1.1", 1016 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1017 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 1018 | "dev": true 1019 | }, 1020 | "read-pkg": { 1021 | "version": "2.0.0", 1022 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", 1023 | "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", 1024 | "dev": true, 1025 | "requires": { 1026 | "load-json-file": "^2.0.0", 1027 | "normalize-package-data": "^2.3.2", 1028 | "path-type": "^2.0.0" 1029 | } 1030 | }, 1031 | "read-pkg-up": { 1032 | "version": "2.0.0", 1033 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", 1034 | "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", 1035 | "dev": true, 1036 | "requires": { 1037 | "find-up": "^2.0.0", 1038 | "read-pkg": "^2.0.0" 1039 | } 1040 | }, 1041 | "regexpp": { 1042 | "version": "2.0.1", 1043 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", 1044 | "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", 1045 | "dev": true 1046 | }, 1047 | "resolve": { 1048 | "version": "1.10.0", 1049 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", 1050 | "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", 1051 | "dev": true, 1052 | "requires": { 1053 | "path-parse": "^1.0.6" 1054 | } 1055 | }, 1056 | "resolve-from": { 1057 | "version": "4.0.0", 1058 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1059 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 1060 | "dev": true 1061 | }, 1062 | "restore-cursor": { 1063 | "version": "2.0.0", 1064 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", 1065 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", 1066 | "dev": true, 1067 | "requires": { 1068 | "onetime": "^2.0.0", 1069 | "signal-exit": "^3.0.2" 1070 | } 1071 | }, 1072 | "rimraf": { 1073 | "version": "2.6.3", 1074 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1075 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 1076 | "dev": true, 1077 | "requires": { 1078 | "glob": "^7.1.3" 1079 | } 1080 | }, 1081 | "run-async": { 1082 | "version": "2.3.0", 1083 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", 1084 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", 1085 | "dev": true, 1086 | "requires": { 1087 | "is-promise": "^2.1.0" 1088 | } 1089 | }, 1090 | "rxjs": { 1091 | "version": "6.4.0", 1092 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", 1093 | "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", 1094 | "dev": true, 1095 | "requires": { 1096 | "tslib": "^1.9.0" 1097 | } 1098 | }, 1099 | "safer-buffer": { 1100 | "version": "2.1.2", 1101 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1102 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 1103 | "dev": true 1104 | }, 1105 | "semver": { 1106 | "version": "5.7.0", 1107 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", 1108 | "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", 1109 | "dev": true 1110 | }, 1111 | "shebang-command": { 1112 | "version": "1.2.0", 1113 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 1114 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 1115 | "dev": true, 1116 | "requires": { 1117 | "shebang-regex": "^1.0.0" 1118 | } 1119 | }, 1120 | "shebang-regex": { 1121 | "version": "1.0.0", 1122 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 1123 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 1124 | "dev": true 1125 | }, 1126 | "signal-exit": { 1127 | "version": "3.0.2", 1128 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1129 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1130 | "dev": true 1131 | }, 1132 | "slice-ansi": { 1133 | "version": "2.1.0", 1134 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", 1135 | "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", 1136 | "dev": true, 1137 | "requires": { 1138 | "ansi-styles": "^3.2.0", 1139 | "astral-regex": "^1.0.0", 1140 | "is-fullwidth-code-point": "^2.0.0" 1141 | } 1142 | }, 1143 | "spdx-correct": { 1144 | "version": "3.1.0", 1145 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", 1146 | "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", 1147 | "dev": true, 1148 | "requires": { 1149 | "spdx-expression-parse": "^3.0.0", 1150 | "spdx-license-ids": "^3.0.0" 1151 | } 1152 | }, 1153 | "spdx-exceptions": { 1154 | "version": "2.2.0", 1155 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", 1156 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", 1157 | "dev": true 1158 | }, 1159 | "spdx-expression-parse": { 1160 | "version": "3.0.0", 1161 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", 1162 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", 1163 | "dev": true, 1164 | "requires": { 1165 | "spdx-exceptions": "^2.1.0", 1166 | "spdx-license-ids": "^3.0.0" 1167 | } 1168 | }, 1169 | "spdx-license-ids": { 1170 | "version": "3.0.4", 1171 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", 1172 | "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", 1173 | "dev": true 1174 | }, 1175 | "sprintf-js": { 1176 | "version": "1.0.3", 1177 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1178 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1179 | "dev": true 1180 | }, 1181 | "string-width": { 1182 | "version": "2.1.1", 1183 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1184 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1185 | "dev": true, 1186 | "requires": { 1187 | "is-fullwidth-code-point": "^2.0.0", 1188 | "strip-ansi": "^4.0.0" 1189 | } 1190 | }, 1191 | "strip-ansi": { 1192 | "version": "4.0.0", 1193 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1194 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1195 | "dev": true, 1196 | "requires": { 1197 | "ansi-regex": "^3.0.0" 1198 | } 1199 | }, 1200 | "strip-bom": { 1201 | "version": "3.0.0", 1202 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 1203 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 1204 | "dev": true 1205 | }, 1206 | "strip-json-comments": { 1207 | "version": "2.0.1", 1208 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1209 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 1210 | "dev": true 1211 | }, 1212 | "supports-color": { 1213 | "version": "5.5.0", 1214 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1215 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1216 | "dev": true, 1217 | "requires": { 1218 | "has-flag": "^3.0.0" 1219 | } 1220 | }, 1221 | "table": { 1222 | "version": "5.2.3", 1223 | "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", 1224 | "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", 1225 | "dev": true, 1226 | "requires": { 1227 | "ajv": "^6.9.1", 1228 | "lodash": "^4.17.11", 1229 | "slice-ansi": "^2.1.0", 1230 | "string-width": "^3.0.0" 1231 | }, 1232 | "dependencies": { 1233 | "ansi-regex": { 1234 | "version": "4.1.0", 1235 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", 1236 | "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", 1237 | "dev": true 1238 | }, 1239 | "string-width": { 1240 | "version": "3.1.0", 1241 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", 1242 | "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", 1243 | "dev": true, 1244 | "requires": { 1245 | "emoji-regex": "^7.0.1", 1246 | "is-fullwidth-code-point": "^2.0.0", 1247 | "strip-ansi": "^5.1.0" 1248 | } 1249 | }, 1250 | "strip-ansi": { 1251 | "version": "5.2.0", 1252 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", 1253 | "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", 1254 | "dev": true, 1255 | "requires": { 1256 | "ansi-regex": "^4.1.0" 1257 | } 1258 | } 1259 | } 1260 | }, 1261 | "text-table": { 1262 | "version": "0.2.0", 1263 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1264 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1265 | "dev": true 1266 | }, 1267 | "through": { 1268 | "version": "2.3.8", 1269 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1270 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1271 | "dev": true 1272 | }, 1273 | "tmp": { 1274 | "version": "0.0.33", 1275 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1276 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1277 | "dev": true, 1278 | "requires": { 1279 | "os-tmpdir": "~1.0.2" 1280 | } 1281 | }, 1282 | "tslib": { 1283 | "version": "1.9.3", 1284 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 1285 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 1286 | "dev": true 1287 | }, 1288 | "type-check": { 1289 | "version": "0.3.2", 1290 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1291 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1292 | "dev": true, 1293 | "requires": { 1294 | "prelude-ls": "~1.1.2" 1295 | } 1296 | }, 1297 | "uri-js": { 1298 | "version": "4.2.2", 1299 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1300 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1301 | "dev": true, 1302 | "requires": { 1303 | "punycode": "^2.1.0" 1304 | } 1305 | }, 1306 | "validate-npm-package-license": { 1307 | "version": "3.0.4", 1308 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 1309 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 1310 | "dev": true, 1311 | "requires": { 1312 | "spdx-correct": "^3.0.0", 1313 | "spdx-expression-parse": "^3.0.0" 1314 | } 1315 | }, 1316 | "which": { 1317 | "version": "1.3.1", 1318 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1319 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1320 | "dev": true, 1321 | "requires": { 1322 | "isexe": "^2.0.0" 1323 | } 1324 | }, 1325 | "wordwrap": { 1326 | "version": "1.0.0", 1327 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1328 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1329 | "dev": true 1330 | }, 1331 | "wrappy": { 1332 | "version": "1.0.2", 1333 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1334 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1335 | "dev": true 1336 | }, 1337 | "write": { 1338 | "version": "1.0.3", 1339 | "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", 1340 | "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", 1341 | "dev": true, 1342 | "requires": { 1343 | "mkdirp": "^0.5.1" 1344 | } 1345 | } 1346 | } 1347 | } 1348 | -------------------------------------------------------------------------------- /lambda/nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "customresource", 3 | "version": "1.0.0", 4 | "description": "Sample customer CloudFormation resource in NodeJS", 5 | "main": "customresource.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": {}, 12 | "devDependencies": { 13 | "acorn": "^6.4.1", 14 | "eslint": "^5.3.0", 15 | "eslint-config-standard": "^11.0.0", 16 | "eslint-plugin-import": "^2.13.0", 17 | "eslint-plugin-node": "^7.0.1", 18 | "eslint-plugin-promise": "^3.8.0", 19 | "eslint-plugin-standard": "^3.1.0", 20 | "minimist": "^1.2.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lambda/python/.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # A comma-separated list of package or module names from where C extensions may 4 | # be loaded. Extensions are loading into the active Python interpreter and may 5 | # run arbitrary code 6 | extension-pkg-whitelist= 7 | 8 | # Add files or directories to the blacklist. They should be base names, not 9 | # paths. 10 | ignore=CVS 11 | 12 | # Add files or directories matching the regex patterns to the blacklist. The 13 | # regex matches against base names, not paths. 14 | ignore-patterns= 15 | 16 | # Python code to execute, usually for sys.path manipulation such as 17 | # pygtk.require(). 18 | #init-hook= 19 | 20 | # Use multiple processes to speed up Pylint. 21 | jobs=1 22 | 23 | # List of plugins (as comma separated values of python modules names) to load, 24 | # usually to register additional checkers. 25 | load-plugins= 26 | 27 | # Pickle collected data for later comparisons. 28 | persistent=yes 29 | 30 | # Specify a configuration file. 31 | #rcfile= 32 | 33 | # When enabled, pylint would attempt to guess common misconfiguration and emit 34 | # user-friendly hints instead of false-positive error messages 35 | suggestion-mode=yes 36 | 37 | # Allow loading of arbitrary C extensions. Extensions are imported into the 38 | # active Python interpreter and may run arbitrary code. 39 | unsafe-load-any-extension=no 40 | 41 | 42 | [MESSAGES CONTROL] 43 | 44 | # Only show warnings with the listed confidence levels. Leave empty to show 45 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED 46 | confidence= 47 | 48 | # Disable the message, report, category or checker with the given id(s). You 49 | # can either give multiple identifiers separated by comma (,) or put this 50 | # option multiple times (only on the command line, not in the configuration 51 | # file where it should appear only once).You can also use "--disable=all" to 52 | # disable everything first and then reenable specific checks. For example, if 53 | # you want to run only the similarities checker, you can use "--disable=all 54 | # --enable=similarities". If you want to run only the classes checker, but have 55 | # no Warning level messages displayed, use"--disable=all --enable=classes 56 | # --disable=W" 57 | disable=print-statement, 58 | parameter-unpacking, 59 | unpacking-in-except, 60 | old-raise-syntax, 61 | backtick, 62 | long-suffix, 63 | old-ne-operator, 64 | old-octal-literal, 65 | import-star-module-level, 66 | non-ascii-bytes-literal, 67 | invalid-unicode-literal, 68 | raw-checker-failed, 69 | bad-inline-option, 70 | locally-disabled, 71 | locally-enabled, 72 | file-ignored, 73 | suppressed-message, 74 | useless-suppression, 75 | deprecated-pragma, 76 | apply-builtin, 77 | basestring-builtin, 78 | buffer-builtin, 79 | cmp-builtin, 80 | coerce-builtin, 81 | execfile-builtin, 82 | file-builtin, 83 | long-builtin, 84 | raw_input-builtin, 85 | reduce-builtin, 86 | standarderror-builtin, 87 | unicode-builtin, 88 | xrange-builtin, 89 | coerce-method, 90 | delslice-method, 91 | getslice-method, 92 | setslice-method, 93 | no-absolute-import, 94 | old-division, 95 | dict-iter-method, 96 | dict-view-method, 97 | next-method-called, 98 | metaclass-assignment, 99 | indexing-exception, 100 | raising-string, 101 | reload-builtin, 102 | oct-method, 103 | hex-method, 104 | nonzero-method, 105 | cmp-method, 106 | input-builtin, 107 | round-builtin, 108 | intern-builtin, 109 | unichr-builtin, 110 | map-builtin-not-iterating, 111 | zip-builtin-not-iterating, 112 | range-builtin-not-iterating, 113 | filter-builtin-not-iterating, 114 | using-cmp-argument, 115 | eq-without-hash, 116 | div-method, 117 | idiv-method, 118 | rdiv-method, 119 | exception-message-attribute, 120 | invalid-str-codec, 121 | sys-max-int, 122 | bad-python3-import, 123 | deprecated-string-function, 124 | deprecated-str-translate-call, 125 | deprecated-itertools-function, 126 | deprecated-types-field, 127 | next-method-defined, 128 | dict-items-not-iterating, 129 | dict-keys-not-iterating, 130 | dict-values-not-iterating, 131 | deprecated-operator-function, 132 | deprecated-urllib-function, 133 | xreadlines-attribute, 134 | deprecated-sys-function, 135 | exception-escape, 136 | comprehension-escape 137 | 138 | # Enable the message, report, category or checker with the given id(s). You can 139 | # either give multiple identifier separated by comma (,) or put this option 140 | # multiple time (only on the command line, not in the configuration file where 141 | # it should appear only once). See also the "--disable" option for examples. 142 | enable=c-extension-no-member 143 | 144 | 145 | [REPORTS] 146 | 147 | # Python expression which should return a note less than 10 (10 is the highest 148 | # note). You have access to the variables errors warning, statement which 149 | # respectively contain the number of errors / warnings messages and the total 150 | # number of statements analyzed. This is used by the global evaluation report 151 | # (RP0004). 152 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 153 | 154 | # Template used to display messages. This is a python new-style format string 155 | # used to format the message information. See doc for all details 156 | #msg-template= 157 | 158 | # Set the output format. Available formats are text, parseable, colorized, json 159 | # and msvs (visual studio).You can also give a reporter class, eg 160 | # mypackage.mymodule.MyReporterClass. 161 | output-format=text 162 | 163 | # Tells whether to display a full report or only the messages 164 | reports=no 165 | 166 | # Activate the evaluation score. 167 | score=yes 168 | 169 | 170 | [REFACTORING] 171 | 172 | # Maximum number of nested blocks for function / method body 173 | max-nested-blocks=5 174 | 175 | # Complete name of functions that never returns. When checking for 176 | # inconsistent-return-statements if a never returning function is called then 177 | # it will be considered as an explicit return statement and no message will be 178 | # printed. 179 | never-returning-functions=optparse.Values,sys.exit 180 | 181 | 182 | [LOGGING] 183 | 184 | # Logging modules to check that the string format arguments are in logging 185 | # function parameter format 186 | logging-modules=logging 187 | 188 | 189 | [SPELLING] 190 | 191 | # Limits count of emitted suggestions for spelling mistakes 192 | max-spelling-suggestions=4 193 | 194 | # Spelling dictionary name. Available dictionaries: none. To make it working 195 | # install python-enchant package. 196 | spelling-dict= 197 | 198 | # List of comma separated words that should not be checked. 199 | spelling-ignore-words= 200 | 201 | # A path to a file that contains private dictionary; one word per line. 202 | spelling-private-dict-file= 203 | 204 | # Tells whether to store unknown words to indicated private dictionary in 205 | # --spelling-private-dict-file option instead of raising a message. 206 | spelling-store-unknown-words=no 207 | 208 | 209 | [MISCELLANEOUS] 210 | 211 | # List of note tags to take in consideration, separated by a comma. 212 | notes=FIXME, 213 | XXX, 214 | TODO 215 | 216 | 217 | [SIMILARITIES] 218 | 219 | # Ignore comments when computing similarities. 220 | ignore-comments=yes 221 | 222 | # Ignore docstrings when computing similarities. 223 | ignore-docstrings=yes 224 | 225 | # Ignore imports when computing similarities. 226 | ignore-imports=no 227 | 228 | # Minimum lines number of a similarity. 229 | min-similarity-lines=4 230 | 231 | 232 | [TYPECHECK] 233 | 234 | # List of decorators that produce context managers, such as 235 | # contextlib.contextmanager. Add to this list to register other decorators that 236 | # produce valid context managers. 237 | contextmanager-decorators=contextlib.contextmanager 238 | 239 | # List of members which are set dynamically and missed by pylint inference 240 | # system, and so shouldn't trigger E1101 when accessed. Python regular 241 | # expressions are accepted. 242 | generated-members= 243 | 244 | # Tells whether missing members accessed in mixin class should be ignored. A 245 | # mixin class is detected if its name ends with "mixin" (case insensitive). 246 | ignore-mixin-members=yes 247 | 248 | # This flag controls whether pylint should warn about no-member and similar 249 | # checks whenever an opaque object is returned when inferring. The inference 250 | # can return multiple potential results while evaluating a Python object, but 251 | # some branches might not be evaluated, which results in partial inference. In 252 | # that case, it might be useful to still emit no-member and other checks for 253 | # the rest of the inferred objects. 254 | ignore-on-opaque-inference=yes 255 | 256 | # List of class names for which member attributes should not be checked (useful 257 | # for classes with dynamically set attributes). This supports the use of 258 | # qualified names. 259 | ignored-classes=optparse.Values,thread._local,_thread._local 260 | 261 | # List of module names for which member attributes should not be checked 262 | # (useful for modules/projects where namespaces are manipulated during runtime 263 | # and thus existing member attributes cannot be deduced by static analysis. It 264 | # supports qualified module names, as well as Unix pattern matching. 265 | ignored-modules= 266 | 267 | # Show a hint with possible names when a member name was not found. The aspect 268 | # of finding the hint is based on edit distance. 269 | missing-member-hint=yes 270 | 271 | # The minimum edit distance a name should have in order to be considered a 272 | # similar match for a missing member name. 273 | missing-member-hint-distance=1 274 | 275 | # The total number of similar names that should be taken in consideration when 276 | # showing a hint for a missing member. 277 | missing-member-max-choices=1 278 | 279 | 280 | [VARIABLES] 281 | 282 | # List of additional names supposed to be defined in builtins. Remember that 283 | # you should avoid to define new builtins when possible. 284 | additional-builtins= 285 | 286 | # Tells whether unused global variables should be treated as a violation. 287 | allow-global-unused-variables=yes 288 | 289 | # List of strings which can identify a callback function by name. A callback 290 | # name must start or end with one of those strings. 291 | callbacks=cb_, 292 | _cb 293 | 294 | # A regular expression matching the name of dummy variables (i.e. expectedly 295 | # not used). 296 | dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ 297 | 298 | # Argument names that match this expression will be ignored. Default to name 299 | # with leading underscore 300 | ignored-argument-names=_.*|^ignored_|^unused_ 301 | 302 | # Tells whether we should check for unused import in __init__ files. 303 | init-import=no 304 | 305 | # List of qualified module names which can have objects that can redefine 306 | # builtins. 307 | redefining-builtins-modules=six.moves,past.builtins,future.builtins,io,builtins 308 | 309 | 310 | [FORMAT] 311 | 312 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 313 | expected-line-ending-format= 314 | 315 | # Regexp for a line that is allowed to be longer than the limit. 316 | ignore-long-lines=^\s*(# )??$ 317 | 318 | # Number of spaces of indent required inside a hanging or continued line. 319 | indent-after-paren=4 320 | 321 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 322 | # tab). 323 | indent-string=' ' 324 | 325 | # Maximum number of characters on a single line. 326 | max-line-length=100 327 | 328 | # Maximum number of lines in a module 329 | max-module-lines=1000 330 | 331 | # List of optional constructs for which whitespace checking is disabled. `dict- 332 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. 333 | # `trailing-comma` allows a space between comma and closing bracket: (a, ). 334 | # `empty-line` allows space-only lines. 335 | no-space-check=trailing-comma, 336 | dict-separator 337 | 338 | # Allow the body of a class to be on the same line as the declaration if body 339 | # contains single statement. 340 | single-line-class-stmt=no 341 | 342 | # Allow the body of an if to be on the same line as the test if there is no 343 | # else. 344 | single-line-if-stmt=no 345 | 346 | 347 | [BASIC] 348 | 349 | # Naming style matching correct argument names 350 | argument-naming-style=snake_case 351 | 352 | # Regular expression matching correct argument names. Overrides argument- 353 | # naming-style 354 | #argument-rgx= 355 | 356 | # Naming style matching correct attribute names 357 | attr-naming-style=snake_case 358 | 359 | # Regular expression matching correct attribute names. Overrides attr-naming- 360 | # style 361 | #attr-rgx= 362 | 363 | # Bad variable names which should always be refused, separated by a comma 364 | bad-names=foo, 365 | bar, 366 | baz, 367 | toto, 368 | tutu, 369 | tata 370 | 371 | # Naming style matching correct class attribute names 372 | class-attribute-naming-style=any 373 | 374 | # Regular expression matching correct class attribute names. Overrides class- 375 | # attribute-naming-style 376 | #class-attribute-rgx= 377 | 378 | # Naming style matching correct class names 379 | class-naming-style=PascalCase 380 | 381 | # Regular expression matching correct class names. Overrides class-naming-style 382 | #class-rgx= 383 | 384 | # Naming style matching correct constant names 385 | const-naming-style=UPPER_CASE 386 | 387 | # Regular expression matching correct constant names. Overrides const-naming- 388 | # style 389 | #const-rgx= 390 | 391 | # Minimum line length for functions/classes that require docstrings, shorter 392 | # ones are exempt. 393 | docstring-min-length=-1 394 | 395 | # Naming style matching correct function names 396 | function-naming-style=snake_case 397 | 398 | # Regular expression matching correct function names. Overrides function- 399 | # naming-style 400 | #function-rgx= 401 | 402 | # Good variable names which should always be accepted, separated by a comma 403 | good-names=i, 404 | j, 405 | k, 406 | ex, 407 | Run, 408 | _ 409 | 410 | # Include a hint for the correct naming format with invalid-name 411 | include-naming-hint=no 412 | 413 | # Naming style matching correct inline iteration names 414 | inlinevar-naming-style=any 415 | 416 | # Regular expression matching correct inline iteration names. Overrides 417 | # inlinevar-naming-style 418 | #inlinevar-rgx= 419 | 420 | # Naming style matching correct method names 421 | method-naming-style=snake_case 422 | 423 | # Regular expression matching correct method names. Overrides method-naming- 424 | # style 425 | #method-rgx= 426 | 427 | # Naming style matching correct module names 428 | module-naming-style=snake_case 429 | 430 | # Regular expression matching correct module names. Overrides module-naming- 431 | # style 432 | #module-rgx= 433 | 434 | # Colon-delimited sets of names that determine each other's naming style when 435 | # the name regexes allow several styles. 436 | name-group= 437 | 438 | # Regular expression which should only match function or class names that do 439 | # not require a docstring. 440 | no-docstring-rgx=^_ 441 | 442 | # List of decorators that produce properties, such as abc.abstractproperty. Add 443 | # to this list to register other decorators that produce valid properties. 444 | property-classes=abc.abstractproperty 445 | 446 | # Naming style matching correct variable names 447 | variable-naming-style=snake_case 448 | 449 | # Regular expression matching correct variable names. Overrides variable- 450 | # naming-style 451 | #variable-rgx= 452 | 453 | 454 | [DESIGN] 455 | 456 | # Maximum number of arguments for function / method 457 | max-args=5 458 | 459 | # Maximum number of attributes for a class (see R0902). 460 | max-attributes=7 461 | 462 | # Maximum number of boolean expressions in a if statement 463 | max-bool-expr=5 464 | 465 | # Maximum number of branch for function / method body 466 | max-branches=12 467 | 468 | # Maximum number of locals for function / method body 469 | max-locals=15 470 | 471 | # Maximum number of parents for a class (see R0901). 472 | max-parents=7 473 | 474 | # Maximum number of public methods for a class (see R0904). 475 | max-public-methods=20 476 | 477 | # Maximum number of return / yield for function / method body 478 | max-returns=6 479 | 480 | # Maximum number of statements in function / method body 481 | max-statements=50 482 | 483 | # Minimum number of public methods for a class (see R0903). 484 | min-public-methods=2 485 | 486 | 487 | [CLASSES] 488 | 489 | # List of method names used to declare (i.e. assign) instance attributes. 490 | defining-attr-methods=__init__, 491 | __new__, 492 | setUp 493 | 494 | # List of member names, which should be excluded from the protected access 495 | # warning. 496 | exclude-protected=_asdict, 497 | _fields, 498 | _replace, 499 | _source, 500 | _make 501 | 502 | # List of valid names for the first argument in a class method. 503 | valid-classmethod-first-arg=cls 504 | 505 | # List of valid names for the first argument in a metaclass class method. 506 | valid-metaclass-classmethod-first-arg=mcs 507 | 508 | 509 | [IMPORTS] 510 | 511 | # Allow wildcard imports from modules that define __all__. 512 | allow-wildcard-with-all=no 513 | 514 | # Analyse import fallback blocks. This can be used to support both Python 2 and 515 | # 3 compatible code, which means that the block might have code that exists 516 | # only in one or another interpreter, leading to false positives when analysed. 517 | analyse-fallback-blocks=no 518 | 519 | # Deprecated modules which should not be used, separated by a comma 520 | deprecated-modules=regsub, 521 | TERMIOS, 522 | Bastion, 523 | rexec 524 | 525 | # Create a graph of external dependencies in the given file (report RP0402 must 526 | # not be disabled) 527 | ext-import-graph= 528 | 529 | # Create a graph of every (i.e. internal and external) dependencies in the 530 | # given file (report RP0402 must not be disabled) 531 | import-graph= 532 | 533 | # Create a graph of internal dependencies in the given file (report RP0402 must 534 | # not be disabled) 535 | int-import-graph= 536 | 537 | # Force import order to recognize a module as part of the standard 538 | # compatibility libraries. 539 | known-standard-library= 540 | 541 | # Force import order to recognize a module as part of a third party library. 542 | known-third-party=enchant 543 | 544 | 545 | [EXCEPTIONS] 546 | 547 | # Exceptions that will emit a warning when being caught. Defaults to 548 | # "Exception" 549 | overgeneral-exceptions=Exception 550 | -------------------------------------------------------------------------------- /lambda/python/Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.python.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | 8 | [dev-packages] 9 | pylint = "<2.0.0" 10 | 11 | [requires] 12 | python_version = "2.7" 13 | -------------------------------------------------------------------------------- /lambda/python/Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "d284b5c689f35b8d80e02a62a527553d27b5af532a171709347d560279499541" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "2.7" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.python.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": {}, 19 | "develop": { 20 | "astroid": { 21 | "hashes": [ 22 | "sha256:0ef2bf9f07c3150929b25e8e61b5198c27b0dca195e156f0e4d5bdd89185ca1a", 23 | "sha256:fc9b582dba0366e63540982c3944a9230cbc6f303641c51483fa547dcc22393a" 24 | ], 25 | "version": "==1.6.5" 26 | }, 27 | "backports.functools-lru-cache": { 28 | "hashes": [ 29 | "sha256:9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a", 30 | "sha256:f0b0e4eba956de51238e17573b7087e852dfe9854afd2e9c873f73fc0ca0a6dd" 31 | ], 32 | "markers": "python_version == '2.7'", 33 | "version": "==1.5" 34 | }, 35 | "configparser": { 36 | "hashes": [ 37 | "sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a" 38 | ], 39 | "markers": "python_version == '2.7'", 40 | "version": "==3.5.0" 41 | }, 42 | "enum34": { 43 | "hashes": [ 44 | "sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850", 45 | "sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a", 46 | "sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79", 47 | "sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1" 48 | ], 49 | "markers": "python_version < '3.4'", 50 | "version": "==1.1.6" 51 | }, 52 | "futures": { 53 | "hashes": [ 54 | "sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265", 55 | "sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1" 56 | ], 57 | "markers": "python_version == '2.7'", 58 | "version": "==3.2.0" 59 | }, 60 | "isort": { 61 | "hashes": [ 62 | "sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af", 63 | "sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", 64 | "sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" 65 | ], 66 | "version": "==4.3.4" 67 | }, 68 | "lazy-object-proxy": { 69 | "hashes": [ 70 | "sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33", 71 | "sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39", 72 | "sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019", 73 | "sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088", 74 | "sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b", 75 | "sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e", 76 | "sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6", 77 | "sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b", 78 | "sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5", 79 | "sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff", 80 | "sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd", 81 | "sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7", 82 | "sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff", 83 | "sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d", 84 | "sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2", 85 | "sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35", 86 | "sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4", 87 | "sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514", 88 | "sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252", 89 | "sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109", 90 | "sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f", 91 | "sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c", 92 | "sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92", 93 | "sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577", 94 | "sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d", 95 | "sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d", 96 | "sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f", 97 | "sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a", 98 | "sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b" 99 | ], 100 | "version": "==1.3.1" 101 | }, 102 | "mccabe": { 103 | "hashes": [ 104 | "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", 105 | "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" 106 | ], 107 | "version": "==0.6.1" 108 | }, 109 | "pylint": { 110 | "hashes": [ 111 | "sha256:09bc539f85706f2cca720a7ddf28f5c6cf8185708d6cb5bbf7a90a32c3b3b0aa", 112 | "sha256:b8471105f12c73a1b9eee2bb2474080370e062a7290addd215eb34bc4dfe9fd8" 113 | ], 114 | "index": "pypi", 115 | "version": "==1.9.3" 116 | }, 117 | "singledispatch": { 118 | "hashes": [ 119 | "sha256:5b06af87df13818d14f08a028e42f566640aef80805c3b50c5056b086e3c2b9c", 120 | "sha256:833b46966687b3de7f438c761ac475213e53b306740f1abfaa86e1d1aae56aa8" 121 | ], 122 | "markers": "python_version < '3.4'", 123 | "version": "==3.4.0.3" 124 | }, 125 | "six": { 126 | "hashes": [ 127 | "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", 128 | "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" 129 | ], 130 | "version": "==1.11.0" 131 | }, 132 | "wrapt": { 133 | "hashes": [ 134 | "sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6" 135 | ], 136 | "version": "==1.10.11" 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /lambda/python/customresource.py: -------------------------------------------------------------------------------- 1 | '''Custom generic CloudFormation resource example''' 2 | 3 | import json 4 | import logging 5 | import signal 6 | from urllib2 import build_opener, HTTPHandler, Request 7 | 8 | LOGGER = logging.getLogger() 9 | LOGGER.setLevel(logging.INFO) 10 | 11 | 12 | def handler(event, context): 13 | '''Handle Lambda event from AWS''' 14 | # Setup alarm for remaining runtime minus a second 15 | signal.alarm((context.get_remaining_time_in_millis() / 1000) - 1) 16 | try: 17 | LOGGER.info('REQUEST RECEIVED:\n %s', event) 18 | LOGGER.info('REQUEST RECEIVED:\n %s', context) 19 | if event['RequestType'] == 'Create': 20 | LOGGER.info('CREATE!') 21 | send_response(event, context, "SUCCESS", 22 | {"Message": "Resource creation successful!"}) 23 | elif event['RequestType'] == 'Update': 24 | LOGGER.info('UPDATE!') 25 | send_response(event, context, "SUCCESS", 26 | {"Message": "Resource update successful!"}) 27 | elif event['RequestType'] == 'Delete': 28 | LOGGER.info('DELETE!') 29 | send_response(event, context, "SUCCESS", 30 | {"Message": "Resource deletion successful!"}) 31 | else: 32 | LOGGER.info('FAILED!') 33 | send_response(event, context, "FAILED", 34 | {"Message": "Unexpected event received from CloudFormation"}) 35 | except: #pylint: disable=W0702 36 | LOGGER.info('FAILED!') 37 | send_response(event, context, "FAILED", { 38 | "Message": "Exception during processing"}) 39 | 40 | 41 | def send_response(event, context, response_status, response_data): 42 | '''Send a resource manipulation status response to CloudFormation''' 43 | response_body = json.dumps({ 44 | "Status": response_status, 45 | "Reason": "See the details in CloudWatch Log Stream: " + context.log_stream_name, 46 | "PhysicalResourceId": context.log_stream_name, 47 | "StackId": event['StackId'], 48 | "RequestId": event['RequestId'], 49 | "LogicalResourceId": event['LogicalResourceId'], 50 | "Data": response_data 51 | }) 52 | 53 | LOGGER.info('ResponseURL: %s', event['ResponseURL']) 54 | LOGGER.info('ResponseBody: %s', response_body) 55 | 56 | opener = build_opener(HTTPHandler) 57 | request = Request(event['ResponseURL'], data=response_body) 58 | request.add_header('Content-Type', '') 59 | request.add_header('Content-Length', len(response_body)) 60 | request.get_method = lambda: 'PUT' 61 | response = opener.open(request) 62 | LOGGER.info("Status code: %s", response.getcode()) 63 | LOGGER.info("Status message: %s", response.msg) 64 | 65 | 66 | def timeout_handler(_signal, _frame): 67 | '''Handle SIGALRM''' 68 | raise Exception('Time exceeded') 69 | 70 | 71 | signal.signal(signal.SIGALRM, timeout_handler) 72 | --------------------------------------------------------------------------------