├── .gitignore
├── LICENCE
├── README.md
├── alpha-service
├── alpha-service.tfvars
├── deploy.bash
├── modules.tf
├── modules
│ ├── alb-listener
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ ├── autoscaling
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── ecs-service
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── task-definition.json
│ │ └── variables.tf
└── variables.tf
├── base-infra
├── base-infra.tfvars
├── deploy.bash
├── modules.tf
├── modules
│ ├── alb
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ ├── bastion
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ ├── ecs-cluster
│ │ ├── datadog-agent-task-definition.json
│ │ ├── hello-world-task-definition.json
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ ├── ecs-instances
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── user-data.tpl
│ │ └── variables.tf
│ ├── security
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── policies
│ │ │ ├── ecs-instance-policy.json
│ │ │ ├── ecs-instance.json
│ │ │ ├── ecs-service-autoscale.json
│ │ │ └── ecs-service.json
│ │ └── variables.tf
│ └── vpc
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
├── outputs.tf
└── variables.tf
├── beta-service
├── .babelrc
├── .eslintignore
├── .eslintrc
├── beta-service.tfvars
├── deploy.bash
├── modules.tf
├── modules
│ ├── alb-listener
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ ├── autoscaling
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── ecs-service
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── task-definition.json
│ │ └── variables.tf
└── variables.tf
├── bitbucket-pipelines.yml
├── charlie-service
├── .babelrc
├── .eslintignore
├── .eslintrc
├── charlie-service.tfvars
├── deploy.bash
├── modules.tf
├── modules
│ ├── alb-listener
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ ├── autoscaling
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── ecs-service
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── task-definition.json
│ │ └── variables.tf
└── variables.tf
└── demo-api
├── .babelrc
├── .eslintignore
├── .eslintrc
├── Dockerfile
├── README.md
├── package.json
├── src
├── healthcheck
│ └── index.js
├── index.js
├── items
│ └── index.js
├── middleware
│ └── index.js
└── utils.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | npm-debug.log
3 | yarn-error.log
4 | node_modules/
5 | .DS_Store
6 | .terraform
7 | *.tfstate
8 | *.tfstate.backup
9 | .history/
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Jordan Hornblow
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 | # Terraform-ecs-autoscale-alb
2 |
3 | Amazon [EC2 Container Service (ECS)](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/) is a highly scalable, fast, container management service that makes it easy to run, stop, and manage Docker containers on a cluster of EC2 instances (called container instances).
4 |
5 | The idea behind ECS is to create a cluster (a group of container instances managed by ECS), define what Docker containers we want to run (with configuration for each container) and ECS will take care of deploying those containers across the cluster, rolling out new versions and integrating with other AWS infrastructure/services.
6 |
7 | A task definition is required to run a Docker container on an ECS cluster. A task definition specifies various parameters such as which Docker image(s) to use and the repository in which the image is stored, how much CPU and memory to use for the container, which environment variables should be passed to the container when it starts, which logging driver to use (awslogs, syslog etc.).
8 |
9 | ---
10 |
11 | This repo contains Terraform configuration for an ECS cluster running three services (alpha, beta and charlie) with instance and service autoscaling configured at 80% CPU and memory (min and max autoscaling limits can be configured). The three services are sitting behind an Application Load Balancer (ALB) with path based routing set up.
12 |
13 | As far as I could tell the ALB doesn't currently support URL Rewriting so I've had to manually perform this at the application level.
14 |
15 | The code for the demo API is in the [/demo-api](../master/demo-api/) directory and is built and hosted on Docker Hub.
16 |
17 | [](https://hub.docker.com/r/jch254/ecs-demo-api)
18 |
19 |
20 | ## Base-infra components:
21 |
22 | + VPC
23 | + Public and private subnets
24 | + Internet Gateway
25 | + NAT Gateways
26 | + ALB in public subnet with Route53 record
27 | + ECS cluster
28 | + ECS container instances in private subnet with autoscaling configured (running Datadog agent and NGINX serving a default index.html for ALB default action on boot)
29 | + Bastion instance in public subnet (in ASG with a fixed size of one). This only allows SSH access for a specific IP address.
30 |
31 | ## Service components
32 |
33 | - ECS service with autoscaling configured
34 | - ALB listener and target group
35 |
36 | ## Deploying via Bitbucket Pipelines
37 |
38 | Deployment to AWS is automated via Bitbucket Pipelines.
39 |
40 | **Before running pipeline for the first time you must:**
41 |
42 | 1. Enable Bitbucket Pipelines for repository
43 | 1. Create an S3 bucket named 'your-terraform-remote-state' for Terraform remote state via console or CLI
44 | 1. Create a Bitbucket Pipelines IAM user with the required permissions
45 | 1. Set up the following account-level Bitbucket Pipelines environment variables in Bitbucket UI:
46 | - AWS_ACCESS_KEY_ID = PIPELINES_USER_ACCESS_KEY_ID
47 | - AWS_SECRET_ACCESS_KEY = PIPELINES_USER_SECRET_ACCESS_KEY
48 | 1. Set up the following repository-level Bitbucket Pipelines environment variables in Bitbucket UI:
49 | - TF_VAR_ssh_allowed_ip = YOUR_IP
50 | - TF_VAR_acm_arn = YOUR_ACM_CERT_ARN
51 | - TF_VAR_route53_zone_id = YOUR_R53_ZONE_ID
52 | - TF_VAR_datadog_api_key = YOUR_DATADOG_API_KEY
53 | - TF_VAR_key_pair_name = YOUR_KEY_PAIR_NAME
54 | - TF_VAR_bastion_key_pair_name = YOUR_KEY_PAIR_NAME
55 | 1. Edit configuration in the .tfvars file in [/base-infra](../master/base-infra/), [/alpha-service](../master/alpha-service/), [/beta-service](../master/beta-service/) and [/charlie-service](../master/charlie-service/) directories with required values.
56 | 1. Update deploy.bash file in [/base-infra](../master/base-infra/), [/alpha-service](../master/alpha-service/), [/beta-service](../master/beta-service/) and [/charlie-service] (../master/charlie-service/) directories with your remote state bucket name.
57 | 1. Uncomment steps in [/bitbucket-pipelines.yml](../master/bitbucket-pipelines.yml) and commit to repository to trigger the pipeline
58 |
59 | Refer to deploy.bash files for manual deployment steps.
60 |
61 | - TODO: Add comments throughout infra code
62 |
--------------------------------------------------------------------------------
/alpha-service/alpha-service.tfvars:
--------------------------------------------------------------------------------
1 | region = "ap-southeast-2"
2 |
3 | service_name = "alpha-service"
4 |
5 | container_port = "80"
6 |
7 | docker_image = "jch254/ecs-demo-api"
8 |
9 | docker_tag = "latest"
10 |
--------------------------------------------------------------------------------
/alpha-service/deploy.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | cd alpha-service
4 |
5 | terraform remote config -backend=s3 \
6 | -backend-config="bucket=603-terraform-remote-state" \
7 | -backend-config="key=terraform-ecs-autoscale-alb/alpha-service.tfstate" \
8 | -backend-config="region=ap-southeast-2" \
9 | -backend-config="encrypt=true"
10 |
11 | terraform get --update
12 | terraform plan -var-file alpha-service.tfvars
13 | terraform apply -var-file alpha-service.tfvars
14 |
15 | cd ..
16 |
--------------------------------------------------------------------------------
/alpha-service/modules.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = "${var.region}"
3 | }
4 |
5 | data "terraform_remote_state" "base_remote_state" {
6 | backend = "s3"
7 | config {
8 | bucket = "603-terraform-remote-state"
9 | key = "terraform-ecs-autoscale-alb/base-infra.tfstate"
10 | region = "${var.region}"
11 | }
12 | }
13 |
14 | module "alb_listener" {
15 | source = "./modules/alb-listener"
16 |
17 | service_name = "${var.service_name}"
18 | container_port = "${var.container_port}"
19 | vpc_id = "${data.terraform_remote_state.base_remote_state.vpc_id}"
20 | alb_listener_arn = "${data.terraform_remote_state.base_remote_state.alb_listener_arn}"
21 | }
22 |
23 | module "ecs_service" {
24 | source = "./modules/ecs-service"
25 |
26 | service_name = "${var.service_name}"
27 | docker_image = "${var.docker_image}"
28 | docker_tag = "${var.docker_tag}"
29 | container_cpu = "${var.container_cpu}"
30 | container_memory = "${var.container_memory}"
31 | container_port = "${var.container_port}"
32 | region = "${var.region}"
33 | cluster_name = "${data.terraform_remote_state.base_remote_state.cluster_name}"
34 | desired_count = "${var.min_capacity}"
35 | ecs_service_role_arn = "${data.terraform_remote_state.base_remote_state.ecs_service_role_arn}"
36 | target_group_arn = "${module.alb_listener.target_group_arn}"
37 | }
38 |
39 | module "autoscaling" {
40 | source = "./modules/autoscaling"
41 |
42 | service_name = "${var.service_name}"
43 | cluster_name = "${data.terraform_remote_state.base_remote_state.cluster_name}"
44 | ecs_service_autoscale_role_arn = "${data.terraform_remote_state.base_remote_state.ecs_service_autoscale_role_arn}"
45 | min_capacity = "${var.min_capacity}"
46 | max_capacity = "${var.max_capacity}"
47 | }
48 |
--------------------------------------------------------------------------------
/alpha-service/modules/alb-listener/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_alb_target_group" "alpha_service_tg" {
2 | name = "${replace(var.service_name, "/(.{0,28})(.*)/", "$1")}-tg"
3 |
4 | protocol = "HTTP"
5 | port = "${var.container_port}"
6 | vpc_id = "${var.vpc_id}"
7 |
8 | health_check {
9 | path = "/ping"
10 | }
11 | }
12 |
13 | resource "aws_alb_listener_rule" "alpha_service_listener" {
14 | listener_arn = "${var.alb_listener_arn}"
15 | priority = 100
16 |
17 | action {
18 | type = "forward"
19 | target_group_arn = "${aws_alb_target_group.alpha_service_tg.arn}"
20 | }
21 |
22 | condition {
23 | field = "path-pattern"
24 | values = ["/alpha/*"]
25 | }
26 |
27 | depends_on = ["aws_alb_target_group.alpha_service_tg"]
28 | }
29 |
--------------------------------------------------------------------------------
/alpha-service/modules/alb-listener/outputs.tf:
--------------------------------------------------------------------------------
1 | output "target_group_arn" {
2 | value = "${aws_alb_target_group.alpha_service_tg.arn}"
3 | }
4 |
--------------------------------------------------------------------------------
/alpha-service/modules/alb-listener/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "container_port" {
6 | description = "Port that service will listen on"
7 | }
8 |
9 | variable "vpc_id" {
10 | description = "Id of the VPC where service should be deployed"
11 | }
12 |
13 | variable "alb_listener_arn" {
14 | description = "ARN of ALB listener"
15 | }
16 |
--------------------------------------------------------------------------------
/alpha-service/modules/autoscaling/main.tf:
--------------------------------------------------------------------------------
1 | # A CloudWatch alarm that moniors CPU utilization of containers for scaling up
2 | resource "aws_cloudwatch_metric_alarm" "alpha_service_cpu_high" {
3 | alarm_name = "${var.service_name}-cpu-utilization-above-80"
4 | alarm_description = "This alarm monitors ${var.service_name} CPU utilization for scaling up"
5 | comparison_operator = "GreaterThanOrEqualToThreshold"
6 | evaluation_periods = "1"
7 | metric_name = "CPUUtilization"
8 | namespace = "AWS/ECS"
9 | period = "120"
10 | statistic = "Average"
11 | threshold = "80"
12 | alarm_actions = ["${aws_appautoscaling_policy.scale_up.arn}"]
13 |
14 | dimensions {
15 | ClusterName = "${var.cluster_name}"
16 | ServiceName = "${var.service_name}"
17 | }
18 | }
19 |
20 | # A CloudWatch alarm that monitors CPU utilization of containers for scaling down
21 | resource "aws_cloudwatch_metric_alarm" "alpha_service_cpu_low" {
22 | alarm_name = "${var.service_name}-cpu-utilization-below-5"
23 | alarm_description = "This alarm monitors ${var.service_name} CPU utilization for scaling down"
24 | comparison_operator = "LessThanThreshold"
25 | evaluation_periods = "1"
26 | metric_name = "CPUUtilization"
27 | namespace = "AWS/ECS"
28 | period = "120"
29 | statistic = "Average"
30 | threshold = "5"
31 | alarm_actions = ["${aws_appautoscaling_policy.scale_down.arn}"]
32 |
33 | dimensions {
34 | ClusterName = "${var.cluster_name}"
35 | ServiceName = "${var.service_name}"
36 | }
37 | }
38 |
39 | # A CloudWatch alarm that monitors memory utilization of containers for scaling up
40 | resource "aws_cloudwatch_metric_alarm" "alpha_service_memory_high" {
41 | alarm_name = "${var.service_name}-memory-utilization-above-80"
42 | alarm_description = "This alarm monitors ${var.service_name} memory utilization for scaling up"
43 | comparison_operator = "GreaterThanOrEqualToThreshold"
44 | evaluation_periods = "1"
45 | metric_name = "MemoryUtilization"
46 | namespace = "AWS/ECS"
47 | period = "120"
48 | statistic = "Average"
49 | threshold = "80"
50 | alarm_actions = ["${aws_appautoscaling_policy.scale_up.arn}"]
51 |
52 | dimensions {
53 | ClusterName = "${var.cluster_name}"
54 | ServiceName = "${var.service_name}"
55 | }
56 | }
57 |
58 | # A CloudWatch alarm that monitors memory utilization of containers for scaling down
59 | resource "aws_cloudwatch_metric_alarm" "alpha_service_memory_low" {
60 | alarm_name = "${var.service_name}-memory-utilization-below-5"
61 | alarm_description = "This alarm monitors ${var.service_name} memory utilization for scaling down"
62 | comparison_operator = "LessThanThreshold"
63 | evaluation_periods = "1"
64 | metric_name = "MemoryUtilization"
65 | namespace = "AWS/ECS"
66 | period = "120"
67 | statistic = "Average"
68 | threshold = "5"
69 | alarm_actions = ["${aws_appautoscaling_policy.scale_down.arn}"]
70 |
71 | dimensions {
72 | ClusterName = "${var.cluster_name}"
73 | ServiceName = "${var.service_name}"
74 | }
75 | }
76 |
77 | resource "aws_appautoscaling_target" "target" {
78 | resource_id = "service/${var.cluster_name}/${var.service_name}"
79 | role_arn = "${var.ecs_service_autoscale_role_arn}"
80 | scalable_dimension = "ecs:service:DesiredCount"
81 | min_capacity = "${var.min_capacity}"
82 | max_capacity = "${var.max_capacity}"
83 | }
84 |
85 | resource "aws_appautoscaling_policy" "scale_up" {
86 | name = "${var.service_name}-scale-up"
87 | resource_id = "service/${var.cluster_name}/${var.service_name}"
88 | scalable_dimension = "ecs:service:DesiredCount"
89 | adjustment_type = "ChangeInCapacity"
90 | cooldown = 120
91 | metric_aggregation_type = "Average"
92 |
93 | step_adjustment {
94 | metric_interval_lower_bound = 0
95 | scaling_adjustment = 1
96 | }
97 |
98 | depends_on = ["aws_appautoscaling_target.target"]
99 | }
100 |
101 | resource "aws_appautoscaling_policy" "scale_down" {
102 | name = "${var.service_name}-scale-down"
103 | resource_id = "service/${var.cluster_name}/${var.service_name}"
104 | scalable_dimension = "ecs:service:DesiredCount"
105 | adjustment_type = "ChangeInCapacity"
106 | cooldown = 120
107 | metric_aggregation_type = "Average"
108 |
109 | step_adjustment {
110 | metric_interval_upper_bound = 0
111 | scaling_adjustment = -1
112 | }
113 |
114 | depends_on = ["aws_appautoscaling_target.target"]
115 | }
116 |
--------------------------------------------------------------------------------
/alpha-service/modules/autoscaling/outputs.tf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jch254/terraform-ecs-autoscale-alb/ee36aa5462166922123252be846c338b9bd9f1b6/alpha-service/modules/autoscaling/outputs.tf
--------------------------------------------------------------------------------
/alpha-service/modules/autoscaling/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "cluster_name" {
6 | description = "Name of ECS cluster"
7 | }
8 |
9 | variable "ecs_service_autoscale_role_arn" {
10 | description = "ARN of IAM role for ECS service autoscaling"
11 | }
12 |
13 | variable "min_capacity" {
14 | description = "Minimum number of containers to run"
15 | }
16 |
17 | variable "max_capacity" {
18 | description = "Minimum number of containers to run"
19 | }
20 |
--------------------------------------------------------------------------------
/alpha-service/modules/ecs-service/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_cloudwatch_log_group" "alpha_service_lg" {
2 | name = "${var.service_name}"
3 | }
4 |
5 | data "template_file" "task_definition" {
6 | template = "${file("${path.module}/task-definition.json")}"
7 |
8 | vars {
9 | service_name = "${var.service_name}"
10 | docker_image = "${var.docker_image}"
11 | docker_tag = "${var.docker_tag}"
12 | container_cpu = "${var.container_cpu}"
13 | container_memory = "${var.container_memory}"
14 | container_port = "${var.container_port}"
15 | log_group_name = "${aws_cloudwatch_log_group.alpha_service_lg.name}"
16 | log_group_region = "${var.region}"
17 | }
18 | }
19 |
20 | # The ECS task that specifies what Docker containers we need to run the service
21 | resource "aws_ecs_task_definition" "alpha_service" {
22 | family = "${var.service_name}"
23 | container_definitions = "${data.template_file.task_definition.rendered}"
24 | }
25 |
26 | # A long-running ECS service for the alpha_service task
27 | resource "aws_ecs_service" "alpha_service" {
28 | name = "${var.service_name}"
29 | cluster = "${var.cluster_name}"
30 | task_definition = "${aws_ecs_task_definition.alpha_service.arn}"
31 | desired_count = "${var.desired_count}"
32 | deployment_minimum_healthy_percent = 50
33 | deployment_maximum_percent = 100
34 | iam_role = "${var.ecs_service_role_arn}"
35 |
36 | load_balancer {
37 | target_group_arn = "${var.target_group_arn}"
38 | container_name = "${var.service_name}"
39 | container_port = "${var.container_port}"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/alpha-service/modules/ecs-service/outputs.tf:
--------------------------------------------------------------------------------
1 | output "service_name" {
2 | value = "${aws_ecs_service.alpha_service.name}"
3 | }
4 |
--------------------------------------------------------------------------------
/alpha-service/modules/ecs-service/task-definition.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "${service_name}",
4 | "image": "${docker_image}:${docker_tag}",
5 | "cpu": ${container_cpu},
6 | "memory": ${container_memory},
7 | "essential": true,
8 | "portMappings": [
9 | {
10 | "containerPort": ${container_port}
11 | }
12 | ],
13 | "logConfiguration": {
14 | "logDriver": "awslogs",
15 | "options": {
16 | "awslogs-group": "${log_group_name}",
17 | "awslogs-region": "${log_group_region}"
18 | }
19 | },
20 | "environment": [
21 | { "name": "SERVICE_NAME", "value": "${service_name}"}
22 | ]
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/alpha-service/modules/ecs-service/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "docker_image" {
6 | description = "Docker image to run"
7 | }
8 |
9 | variable "docker_tag" {
10 | description = "Tag of docker image to run"
11 | }
12 |
13 | variable "container_cpu" {
14 | description = "The number of cpu units to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
15 | }
16 |
17 | variable "container_memory" {
18 | description = "The number of MiB of memory to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
19 | }
20 |
21 | variable "container_port" {
22 | description = "Port that service will listen on"
23 | }
24 |
25 | variable "region" {
26 | description = "AWS region to deploy to (e.g. ap-southeast-2)"
27 | }
28 |
29 | variable "cluster_name" {
30 | description = "Name of ECS cluster"
31 | }
32 |
33 | variable "desired_count" {
34 | description = "Initial number of containers to run"
35 | }
36 |
37 | variable "ecs_service_role_arn" {
38 | description = "ARN of IAM role for ECS service"
39 | }
40 |
41 | variable "target_group_arn" {
42 | description = "ARN of ALB target group for service"
43 | }
44 |
--------------------------------------------------------------------------------
/alpha-service/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | description = "AWS region to deploy to (e.g. ap-southeast-2)"
3 | }
4 |
5 | variable "service_name" {
6 | description = "Name of service"
7 | }
8 |
9 | variable "container_port" {
10 | description = "Port that service will listen on"
11 | }
12 |
13 | variable "docker_image" {
14 | description = "Docker image to run"
15 | }
16 |
17 | variable "docker_tag" {
18 | description = "Tag of docker image to run"
19 | }
20 |
21 | variable "container_cpu" {
22 | description = "The number of cpu units to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
23 | default = "256"
24 | }
25 |
26 | variable "container_memory" {
27 | description = "The number of MiB of memory to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
28 | default = "256"
29 | }
30 |
31 | variable "min_capacity" {
32 | description = "Minimum number of containers to run"
33 | default = 2
34 | }
35 |
36 | variable "max_capacity" {
37 | description = "Minimum number of containers to run"
38 | default = 6
39 | }
40 |
--------------------------------------------------------------------------------
/base-infra/base-infra.tfvars:
--------------------------------------------------------------------------------
1 | region = "ap-southeast-2"
2 |
3 | alb_dns_name = "ecs-demo.jch254.com"
4 |
5 | cluster_name = "ecs-demo"
6 |
7 | instance_type = "t2.micro"
8 |
9 | bastion_instance_type = "t2.micro"
10 |
--------------------------------------------------------------------------------
/base-infra/deploy.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | cd base-infra
4 |
5 | terraform remote config -backend=s3 \
6 | -backend-config="bucket=603-terraform-remote-state" \
7 | -backend-config="key=terraform-ecs-autoscale-alb/base-infra.tfstate" \
8 | -backend-config="region=ap-southeast-2" \
9 | -backend-config="encrypt=true"
10 |
11 | terraform get --update
12 | terraform plan -var-file base-infra.tfvars
13 | terraform apply -var-file base-infra.tfvars
14 |
15 | cd ..
16 |
--------------------------------------------------------------------------------
/base-infra/modules.tf:
--------------------------------------------------------------------------------
1 | # Configure the AWS Provider
2 | provider "aws" {
3 | region = "${var.region}"
4 | }
5 |
6 | module "vpc" {
7 | source = "./modules/vpc"
8 |
9 | region = "${var.region}"
10 | az_count = "${var.az_count}"
11 | }
12 |
13 | module "security" {
14 | source = "./modules/security"
15 |
16 | vpc_id = "${module.vpc.vpc_id}"
17 | vpc_cidr_block = "${module.vpc.vpc_cidr_block}"
18 | ssh_allowed_ip = "${var.ssh_allowed_ip}"
19 | }
20 |
21 | module "bastion" {
22 | source = "./modules/bastion"
23 |
24 | instance_type = "${var.bastion_instance_type}"
25 | key_pair_name = "${var.bastion_key_pair_name}"
26 | security_group_internal_id = "${module.security.internal_id}"
27 | security_group_ssh_id = "${module.security.ssh_id}"
28 | ami = "${lookup(var.bastion_ami, var.region)}"
29 | bastion_subnet_ids = "${module.vpc.subnet_public_ids}"
30 | }
31 |
32 | module "alb" {
33 | source = "./modules/alb"
34 |
35 | security_group_internal_id = "${module.security.internal_id}"
36 | security_group_inbound_id = "${module.security.inbound_id}"
37 | alb_subnet_ids = "${module.vpc.subnet_public_ids}"
38 | vpc_id = "${module.vpc.vpc_id}"
39 | acm_arn = "${var.acm_arn}"
40 | route53_zone_id = "${var.route53_zone_id}"
41 | alb_dns_name = "${var.alb_dns_name}"
42 | }
43 |
44 | module "ecs_cluster" {
45 | source = "./modules/ecs-cluster"
46 |
47 | cluster_name = "${var.cluster_name}"
48 | datadog_api_key = "${var.datadog_api_key}"
49 | }
50 |
51 | module "ecs_instances" {
52 | source = "./modules/ecs-instances"
53 |
54 | cluster_name = "${module.ecs_cluster.cluster_name}"
55 | dd_agent_task_name = "${module.ecs_cluster.dd_agent_task_name}"
56 | hello_world_task_name = "${module.ecs_cluster.hello_world_task_name}"
57 | instance_type = "${var.instance_type}"
58 | key_pair_name = "${var.key_pair_name}"
59 | instance_profile_name = "${module.security.ecs_instance_profile_name}"
60 | security_group_ecs_instance_id = "${module.security.internal_id}"
61 | ami = "${lookup(var.ami, var.region)}"
62 | asg_min = "${var.asg_min}"
63 | asg_max = "${var.asg_max}"
64 | ecs_cluster_subnet_ids = "${module.vpc.subnet_private_ids}"
65 | target_group_arn = "${module.alb.target_group_arn}"
66 | }
67 |
--------------------------------------------------------------------------------
/base-infra/modules/alb/main.tf:
--------------------------------------------------------------------------------
1 | # Application load balancer that distributes load between the instances
2 | resource "aws_alb" "instance_alb" {
3 | name = "instance-alb"
4 | internal = false
5 |
6 | security_groups = [
7 | "${var.security_group_internal_id}",
8 | "${var.security_group_inbound_id}",
9 | ]
10 |
11 | subnets = ["${split(",", var.alb_subnet_ids)}"]
12 | }
13 |
14 | # Default ALB target group that defines the default port/protocol the instances will listen on
15 | resource "aws_alb_target_group" "instance_tg" {
16 | name = "instance-tg"
17 | protocol = "HTTP"
18 | port = "80"
19 | vpc_id = "${var.vpc_id}"
20 |
21 | health_check {
22 | path = "/"
23 | }
24 | }
25 |
26 | # ALB listener that checks for connection requests from clients using the port/protocol specified
27 | # These requests are then forwarded to one or more target groups, based on the rules defined
28 | resource "aws_alb_listener" "instance_listener" {
29 | load_balancer_arn = "${aws_alb.instance_alb.arn}"
30 | port = "443"
31 | protocol = "HTTPS"
32 | ssl_policy = "ELBSecurityPolicy-2015-05"
33 | certificate_arn = "${var.acm_arn}"
34 |
35 | default_action {
36 | target_group_arn = "${aws_alb_target_group.instance_tg.arn}"
37 | type = "forward"
38 | }
39 |
40 | depends_on = ["aws_alb_target_group.instance_tg"]
41 | }
42 |
43 | # Route 53 DNS record for the application load balancer
44 | resource "aws_route53_record" "alb_record" {
45 | zone_id = "${var.route53_zone_id}"
46 | name = "${var.alb_dns_name}"
47 | type = "A"
48 |
49 | alias {
50 | name = "${aws_alb.instance_alb.dns_name}"
51 | zone_id = "${aws_alb.instance_alb.zone_id}"
52 | evaluate_target_health = false
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/base-infra/modules/alb/outputs.tf:
--------------------------------------------------------------------------------
1 | output "alb_listener_arn" {
2 | value = "${aws_alb_listener.instance_listener.arn}"
3 | }
4 |
5 | output "target_group_arn" {
6 | value = "${aws_alb_target_group.instance_tg.arn}"
7 | }
8 |
--------------------------------------------------------------------------------
/base-infra/modules/alb/variables.tf:
--------------------------------------------------------------------------------
1 | variable "security_group_internal_id" {
2 | description = "Id of security group allowing internal traffic"
3 | }
4 |
5 | variable "security_group_inbound_id" {
6 | description = "Id of security group allowing inbound traffic"
7 | }
8 |
9 | variable "alb_subnet_ids" {
10 | description = "Comma-separated list of subnets where ALB should be deployed"
11 | }
12 |
13 | variable "vpc_id" {
14 | description = "Id of VPC where ALB will live"
15 | }
16 |
17 | variable "acm_arn" {
18 | description = "ARN of ACM SSL certificate"
19 | }
20 |
21 | variable "route53_zone_id" {
22 | description = "Route 53 Hosted Zone ID"
23 | }
24 |
25 | variable "alb_dns_name" {
26 | description = "DNS name for ALB"
27 | }
28 |
--------------------------------------------------------------------------------
/base-infra/modules/bastion/main.tf:
--------------------------------------------------------------------------------
1 | # Launch configuration for each bastion
2 | resource "aws_launch_configuration" "bastion" {
3 | name_prefix = "bastion-"
4 | instance_type = "${var.instance_type}"
5 | key_name = "${var.key_pair_name}"
6 | associate_public_ip_address = true
7 | image_id = "${var.ami}"
8 |
9 | security_groups = [
10 | "${var.security_group_internal_id}",
11 | "${var.security_group_ssh_id}",
12 | ]
13 |
14 | # Important note: whenever using a launch configuration with an auto scaling
15 | # group, you must set create_before_destroy = true. However, as soon as you
16 | # set create_before_destroy = true in one resource, you must also set it in
17 | # every resource that it depends on, or we'll get an error about cyclic
18 | # dependencies (especially when removing resources). For more info, see:
19 | #
20 | # https://www.terraform.io/docs/providers/aws/r/launch_configuration.html
21 | # https://terraform.io/docs/configuration/resources.html
22 | lifecycle { create_before_destroy = true }
23 | }
24 |
25 | # Autoscaling group that specifies how we want to scale the bastions
26 | resource "aws_autoscaling_group" "bastion" {
27 | name = "bastion"
28 | min_size = "1"
29 | max_size = "1"
30 | launch_configuration = "${aws_launch_configuration.bastion.name}"
31 | vpc_zone_identifier = ["${split(",", var.bastion_subnet_ids)}"]
32 | health_check_type = "EC2"
33 |
34 | lifecycle { create_before_destroy = true }
35 |
36 | tag {
37 | key = "Name"
38 | value = "bastion"
39 | propagate_at_launch = true
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/base-infra/modules/bastion/outputs.tf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jch254/terraform-ecs-autoscale-alb/ee36aa5462166922123252be846c338b9bd9f1b6/base-infra/modules/bastion/outputs.tf
--------------------------------------------------------------------------------
/base-infra/modules/bastion/variables.tf:
--------------------------------------------------------------------------------
1 | variable "instance_type" {
2 | description = "Instance type of bastion instance (e.g. t2.micro)"
3 | }
4 |
5 | variable "key_pair_name" {
6 | description = "Name of the Key Pair that can be used to access bastion instance"
7 | }
8 |
9 | variable "ami" {
10 | description = "AMI of bastion instance"
11 | }
12 |
13 | variable "security_group_internal_id" {
14 | description = "Id of security group allowing internal traffic"
15 | }
16 |
17 | variable "security_group_ssh_id" {
18 | description = "Id of security group allowing SSH traffic"
19 | }
20 |
21 | variable "bastion_subnet_ids" {
22 | description = "Comma-separated list of subnets where bastion instance should be deployed"
23 | }
24 |
--------------------------------------------------------------------------------
/base-infra/modules/ecs-cluster/datadog-agent-task-definition.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "environment": [
4 | {
5 | "name": "API_KEY",
6 | "value": "${datadog_api_key}"
7 | }
8 | ],
9 | "mountPoints": [
10 | {
11 | "sourceVolume": "docker_sock",
12 | "containerPath": "/var/run/docker.sock",
13 | "readOnly": false
14 | },
15 | {
16 | "sourceVolume": "proc",
17 | "containerPath": "/host/proc",
18 | "readOnly": true
19 | },
20 | {
21 | "sourceVolume": "cgroup",
22 | "containerPath": "/host/sys/fs/cgroup",
23 | "readOnly": true
24 | }
25 | ],
26 | "name": "dd-agent",
27 | "image": "datadog/docker-dd-agent:ecs",
28 | "cpu": 10,
29 | "memory": 128,
30 | "essential": true
31 | }
32 | ]
33 |
--------------------------------------------------------------------------------
/base-infra/modules/ecs-cluster/hello-world-task-definition.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "environment": [],
4 | "mountPoints": [
5 | {
6 | "sourceVolume": "www",
7 | "containerPath": "/usr/share/nginx/html",
8 | "readOnly": true
9 | }
10 | ],
11 | "portMappings": [
12 | {
13 | "containerPort": 80,
14 | "hostPort": 80
15 | }
16 | ],
17 | "name": "hello-world",
18 | "image": "nginx",
19 | "cpu": 10,
20 | "memory": 128,
21 | "essential": true
22 | }
23 | ]
24 |
--------------------------------------------------------------------------------
/base-infra/modules/ecs-cluster/main.tf:
--------------------------------------------------------------------------------
1 | # The ECS Cluster
2 | resource "aws_ecs_cluster" "ecs_cluster" {
3 | name = "${var.cluster_name}"
4 | }
5 |
6 | # The Datadog agent task definition
7 | data "template_file" "datadog_agent_task_definition" {
8 | template = "${file("${path.module}/datadog-agent-task-definition.json")}"
9 |
10 | vars {
11 | datadog_api_key = "${var.datadog_api_key}"
12 | }
13 | }
14 |
15 | # The hello world task definition
16 | data "template_file" "hello_world_task_definition" {
17 | template = "${file("${path.module}/hello-world-task-definition.json")}"
18 | }
19 |
20 | # The ECS task that specifies which Docker container we need to run the Datadog agent container
21 | resource "aws_ecs_task_definition" "datadog_agent" {
22 | family = "dd-agent-task"
23 | volume {
24 | name = "docker_sock"
25 | host_path = "/var/run/docker.sock"
26 | }
27 | volume {
28 | name = "proc"
29 | host_path = "/proc/"
30 | }
31 | volume {
32 | name = "cgroup"
33 | host_path = "/cgroup/"
34 | }
35 | container_definitions = "${data.template_file.datadog_agent_task_definition.rendered}"
36 | }
37 |
38 | # The ECS task that specifies which Docker container we need to run the hello world container
39 | resource "aws_ecs_task_definition" "hello_world" {
40 | family = "hello-world"
41 | volume {
42 | name = "www"
43 | host_path = "/var/www/html"
44 | }
45 | container_definitions = "${data.template_file.hello_world_task_definition.rendered}"
46 | }
47 |
--------------------------------------------------------------------------------
/base-infra/modules/ecs-cluster/outputs.tf:
--------------------------------------------------------------------------------
1 | output "cluster_name" {
2 | value = "${aws_ecs_cluster.ecs_cluster.name}"
3 | }
4 |
5 | output "dd_agent_task_name" {
6 | value = "${aws_ecs_task_definition.datadog_agent.family}"
7 | }
8 |
9 | output "hello_world_task_name" {
10 | value = "${aws_ecs_task_definition.hello_world.family}"
11 | }
12 |
--------------------------------------------------------------------------------
/base-infra/modules/ecs-cluster/variables.tf:
--------------------------------------------------------------------------------
1 | variable "cluster_name" {
2 | description = "Name of ECS cluster"
3 | }
4 |
5 | variable "datadog_api_key" {
6 | description = "Datadog API key"
7 | }
8 |
--------------------------------------------------------------------------------
/base-infra/modules/ecs-instances/main.tf:
--------------------------------------------------------------------------------
1 | # User data template that specifies how to bootstrap each instance
2 | data "template_file" "user_data" {
3 | template = "${file("${path.module}/user-data.tpl")}"
4 |
5 | vars {
6 | cluster_name = "${var.cluster_name}"
7 | dd_agent_task_name = "${var.dd_agent_task_name}"
8 | hello_world_task_name = "${var.hello_world_task_name}"
9 | }
10 | }
11 |
12 | # The launch configuration for each EC2 Instance that will run in the cluster
13 | resource "aws_launch_configuration" "ecs_instance" {
14 | name_prefix = "${var.cluster_name}-instance-"
15 | instance_type = "${var.instance_type}"
16 | key_name = "${var.key_pair_name}"
17 | iam_instance_profile = "${var.instance_profile_name}"
18 | security_groups = ["${var.security_group_ecs_instance_id}"]
19 | image_id = "${var.ami}"
20 | user_data = "${data.template_file.user_data.rendered}"
21 |
22 | # Important note: whenever using a launch configuration with an auto scaling
23 | # group, you must set create_before_destroy = true. However, as soon as you
24 | # set create_before_destroy = true in one resource, you must also set it in
25 | # every resource that it depends on, or we'll get an error about cyclic
26 | # dependencies (especially when removing resources). For more info, see:
27 | #
28 | # https://www.terraform.io/docs/providers/aws/r/launch_configuration.html
29 | # https://terraform.io/docs/configuration/resources.html
30 | lifecycle { create_before_destroy = true }
31 | }
32 |
33 | # The auto scaling group that specifies how we want to scale the number of EC2 Instances in the cluster
34 | resource "aws_autoscaling_group" "ecs_cluster" {
35 | name = "${var.cluster_name}-instances"
36 | min_size = "${var.asg_min}"
37 | max_size = "${var.asg_max}"
38 | launch_configuration = "${aws_launch_configuration.ecs_instance.name}"
39 | vpc_zone_identifier = ["${split(",", var.ecs_cluster_subnet_ids)}"]
40 | health_check_type = "EC2"
41 | target_group_arns = ["${var.target_group_arn}"]
42 |
43 | lifecycle { create_before_destroy = true }
44 |
45 | tag {
46 | key = "Name"
47 | value = "${var.cluster_name}-instance"
48 | propagate_at_launch = true
49 | }
50 | }
51 |
52 | resource "aws_autoscaling_policy" "scale_up" {
53 | name = "${var.cluster_name}-instances-scale-up"
54 | scaling_adjustment = 1
55 | adjustment_type = "ChangeInCapacity"
56 | cooldown = 300
57 | autoscaling_group_name = "${aws_autoscaling_group.ecs_cluster.name}"
58 | }
59 |
60 | resource "aws_autoscaling_policy" "scale_down" {
61 | name = "${var.cluster_name}-instances-scale-down"
62 | scaling_adjustment = -1
63 | adjustment_type = "ChangeInCapacity"
64 | cooldown = 300
65 | autoscaling_group_name = "${aws_autoscaling_group.ecs_cluster.name}"
66 | }
67 |
68 | # A CloudWatch alarm that monitors CPU utilization of cluster instances for scaling up
69 | resource "aws_cloudwatch_metric_alarm" "ecs_cluster_instances_cpu_high" {
70 | alarm_name = "${var.cluster_name}-instances-CPU-Utilization-Above-80"
71 | alarm_description = "This alarm monitors ${var.cluster_name} instances CPU utilization for scaling up"
72 | comparison_operator = "GreaterThanOrEqualToThreshold"
73 | evaluation_periods = "1"
74 | metric_name = "CPUUtilization"
75 | namespace = "AWS/EC2"
76 | period = "300"
77 | statistic = "Average"
78 | threshold = "80"
79 | alarm_actions = ["${aws_autoscaling_policy.scale_up.arn}"]
80 |
81 | dimensions {
82 | AutoScalingGroupName = "${aws_autoscaling_group.ecs_cluster.name}"
83 | }
84 | }
85 |
86 | # A CloudWatch alarm that monitors CPU utilization of cluster instances for scaling down
87 | resource "aws_cloudwatch_metric_alarm" "ecs_cluster_instances_cpu_low" {
88 | alarm_name = "${var.cluster_name}-instances-CPU-Utilization-Below-5"
89 | alarm_description = "This alarm monitors ${var.cluster_name} instances CPU utilization for scaling down"
90 | comparison_operator = "LessThanThreshold"
91 | evaluation_periods = "1"
92 | metric_name = "CPUUtilization"
93 | namespace = "AWS/EC2"
94 | period = "300"
95 | statistic = "Average"
96 | threshold = "5"
97 | alarm_actions = ["${aws_autoscaling_policy.scale_down.arn}"]
98 |
99 | dimensions {
100 | AutoScalingGroupName = "${aws_autoscaling_group.ecs_cluster.name}"
101 | }
102 | }
103 |
104 | # A CloudWatch alarm that monitors memory utilization of cluster instances for scaling up
105 | resource "aws_cloudwatch_metric_alarm" "ecs_cluster_instances_memory_high" {
106 | alarm_name = "${var.cluster_name}-instances-Memory-Utilization-Above-80"
107 | alarm_description = "This alarm monitors ${var.cluster_name} instances memory utilization for scaling up"
108 | comparison_operator = "GreaterThanOrEqualToThreshold"
109 | evaluation_periods = "1"
110 | metric_name = "MemoryUtilization"
111 | namespace = "AWS/EC2"
112 | period = "300"
113 | statistic = "Average"
114 | threshold = "80"
115 | alarm_actions = ["${aws_autoscaling_policy.scale_down.arn}"]
116 |
117 | dimensions {
118 | AutoScalingGroupName = "${aws_autoscaling_group.ecs_cluster.name}"
119 | }
120 | }
121 |
122 | # A CloudWatch alarm that monitors memory utilization of cluster instances for scaling down
123 | resource "aws_cloudwatch_metric_alarm" "ecs_cluster_instances_memory_low" {
124 | alarm_name = "${var.cluster_name}-instances-Memory-Utilization-Below-5"
125 | alarm_description = "This alarm monitors ${var.cluster_name} instances memory utilization for scaling down"
126 | comparison_operator = "LessThanThreshold"
127 | evaluation_periods = "1"
128 | metric_name = "MemoryUtilization"
129 | namespace = "AWS/EC2"
130 | period = "300"
131 | statistic = "Average"
132 | threshold = "5"
133 | alarm_actions = ["${aws_autoscaling_policy.scale_down.arn}"]
134 |
135 | dimensions {
136 | AutoScalingGroupName = "${aws_autoscaling_group.ecs_cluster.name}"
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/base-infra/modules/ecs-instances/outputs.tf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jch254/terraform-ecs-autoscale-alb/ee36aa5462166922123252be846c338b9bd9f1b6/base-infra/modules/ecs-instances/outputs.tf
--------------------------------------------------------------------------------
/base-infra/modules/ecs-instances/user-data.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 | exec > >(tee /var/log/user-data.log|logger -t user-data -s 2>/dev/console) 2>&1
3 |
4 | echo Begin: user-data
5 |
6 | echo Begin: update and install packages
7 | yum update -y
8 | yum install -y aws-cli jq
9 | echo End: update and install packages
10 |
11 | echo Begin: create hello world index.html
12 | mkdir -p /var/www/html
13 | echo '
Hello world from ${cluster_name}!
' >> /var/www/html/index.html
14 | echo End: create hello world index.html
15 |
16 | echo Begin: start ECS
17 | cluster="${cluster_name}"
18 | echo ECS_CLUSTER=$cluster >> /etc/ecs/ecs.config
19 | start ecs
20 | until $(curl --output /dev/null --silent --head --fail http://localhost:51678/v1/metadata); do
21 | printf '.'
22 | sleep 1
23 | done
24 | echo End: start ECS
25 |
26 | echo Begin: set up datadog and hello world ECS tasks
27 | dd_task_def="${dd_agent_task_name}"
28 | hello_world_task_def="${hello_world_task_name}"
29 | instance_arn=$(curl -s http://localhost:51678/v1/metadata | jq -r '. | .ContainerInstanceArn' | awk -F/ '{print $NF}' )
30 | az=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)
31 | region=$${az:0:$${#az} - 1}
32 |
33 | echo "
34 | cluster=$cluster
35 | az=$az
36 | region=$region
37 | aws ecs start-task --cluster $cluster --task-definition $dd_task_def --container-instances $instance_arn --region $region
38 | aws ecs start-task --cluster $cluster --task-definition $hello_world_task_def --container-instances $instance_arn --region $region
39 | " >> /etc/rc.local
40 | echo End: set up datadog and hello world ECS tasks
41 |
42 | echo End: user-data
43 |
--------------------------------------------------------------------------------
/base-infra/modules/ecs-instances/variables.tf:
--------------------------------------------------------------------------------
1 | variable "cluster_name" {
2 | description = "Name of ECS cluster"
3 | }
4 |
5 | variable "dd_agent_task_name" {
6 | description = "Name of Datadog agent ECS task"
7 | }
8 |
9 | variable "hello_world_task_name" {
10 | description = "Name of 'hello world' ECS task"
11 | }
12 |
13 | variable "instance_type" {
14 | description = "Instance type of each EC2 instance in the ECS cluster"
15 | }
16 |
17 | variable "key_pair_name" {
18 | description = "Name of the Key Pair that can be used to SSH to each EC2 instance in the ECS cluster"
19 | }
20 |
21 | variable "instance_profile_name" {
22 | description = "Name of IAM instance profile for ECS instances"
23 | }
24 |
25 | variable "security_group_ecs_instance_id" {
26 | description = "Id of security group allowing internal traffic"
27 | }
28 |
29 | variable "ami" {
30 | description = "AMI of each EC2 instance in the ECS cluster"
31 | }
32 |
33 | variable "asg_min" {
34 | description = "Minimum number of EC2 instances to run in the ECS cluster"
35 | }
36 |
37 | variable "asg_max" {
38 | description = "Maximum number of EC2 instances to run in the ECS cluster"
39 | }
40 |
41 | variable "ecs_cluster_subnet_ids" {
42 | description = "Comma-separated list of subnets where EC2 instances should be deployed"
43 | }
44 |
45 | variable "target_group_arn" {
46 | default = "ALB Target group ARN"
47 | }
48 |
--------------------------------------------------------------------------------
/base-infra/modules/security/main.tf:
--------------------------------------------------------------------------------
1 | # Security group allowing internal traffic (inside VPC)
2 | resource "aws_security_group" "internal" {
3 | vpc_id = "${var.vpc_id}"
4 | name = "internal"
5 | description = "Allow internal traffic"
6 |
7 | ingress {
8 | from_port = 0
9 | to_port = 65535
10 | protocol = "tcp"
11 | cidr_blocks = ["${var.vpc_cidr_block}"]
12 | }
13 |
14 | egress {
15 | from_port = 0
16 | to_port = 0
17 | protocol = "-1"
18 | cidr_blocks = ["0.0.0.0/0"]
19 | }
20 |
21 | tags {
22 | Name = "internal"
23 | }
24 | }
25 |
26 | # Security group allowing SSH traffic from a designated IP address (var.ssh_allowed_ip)
27 | resource "aws_security_group" "ssh" {
28 | vpc_id = "${var.vpc_id}"
29 | name = "ssh"
30 | description = "Allow SSH inbound traffic"
31 |
32 | ingress {
33 | from_port = 22
34 | to_port = 22
35 | protocol = "tcp"
36 | cidr_blocks = ["${var.ssh_allowed_ip}/32"]
37 | }
38 |
39 | egress {
40 | from_port = 0
41 | to_port = 0
42 | protocol = "-1"
43 | cidr_blocks = ["0.0.0.0/0"]
44 | }
45 |
46 | tags {
47 | Name = "ssh"
48 | }
49 | }
50 |
51 | # Security group allowing inbound HTTPS from anywhere
52 | resource "aws_security_group" "inbound" {
53 | vpc_id = "${var.vpc_id}"
54 | name = "inbound"
55 | description = "Allow inbound HTTPS traffic"
56 |
57 | ingress {
58 | from_port = 443
59 | to_port = 443
60 | protocol = "tcp"
61 | cidr_blocks = ["0.0.0.0/0"]
62 | }
63 |
64 | egress {
65 | from_port = 0
66 | to_port = 0
67 | protocol = "-1"
68 | cidr_blocks = ["0.0.0.0/0"]
69 | }
70 |
71 | tags {
72 | Name = "inbound"
73 | }
74 | }
75 |
76 | # An IAM instance profile we attach to the EC2 instances in the cluster
77 | resource "aws_iam_instance_profile" "ecs_instance" {
78 | name = "ecs-instance"
79 | roles = ["${aws_iam_role.ecs_instance.name}"]
80 |
81 | lifecycle { create_before_destroy = true }
82 | }
83 |
84 | # An IAM role that we attach to the EC2 Instances in the cluster
85 | resource "aws_iam_role" "ecs_instance" {
86 | name = "ecs-instance"
87 | assume_role_policy = "${file("${path.module}/policies/ecs-instance.json")}"
88 |
89 | lifecycle { create_before_destroy = true }
90 | }
91 |
92 | # IAM policy we add to ECS cluster instances that allows them to do their thing
93 | resource "aws_iam_role_policy" "ecs_instance_policy" {
94 | name = "ecs-instance-policy"
95 | role = "${aws_iam_role.ecs_instance.id}"
96 | policy = "${file("${path.module}/policies/ecs-instance-policy.json")}"
97 |
98 | lifecycle { create_before_destroy = true }
99 | }
100 |
101 | # An IAM Role that we attach to ECS services
102 | resource "aws_iam_role" "ecs_service" {
103 | name = "ecs-service"
104 | assume_role_policy = "${file("${path.module}/policies/ecs-service.json")}"
105 | }
106 |
107 | # Managed IAM Policy for ECS services to communicate with EC2 Instances
108 | resource "aws_iam_role_policy_attachment" "ecs_service" {
109 | role = "${aws_iam_role.ecs_service.name}"
110 | policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole"
111 | }
112 |
113 | # An IAM Role for ECS service autoscaling
114 | resource "aws_iam_role" "ecs_service_autoscale" {
115 | name = "ecs-service-autoscale"
116 | assume_role_policy = "${file("${path.module}/policies/ecs-service-autoscale.json")}"
117 | }
118 |
119 | # Managed IAM Policy for ECS service autoscaling
120 | resource "aws_iam_role_policy_attachment" "ecs_service_autoscale" {
121 | role = "${aws_iam_role.ecs_service_autoscale.name}"
122 | policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole"
123 | }
124 |
--------------------------------------------------------------------------------
/base-infra/modules/security/outputs.tf:
--------------------------------------------------------------------------------
1 | output "internal_id" {
2 | value = "${aws_security_group.internal.id}"
3 | }
4 |
5 | output "inbound_id" {
6 | value = "${aws_security_group.inbound.id}"
7 | }
8 |
9 | output "ssh_id" {
10 | value = "${aws_security_group.ssh.id}"
11 | }
12 |
13 | output "ecs_instance_profile_name" {
14 | value = "${aws_iam_instance_profile.ecs_instance.name}"
15 | }
16 |
17 | output "ecs_service_role_arn" {
18 | value = "${aws_iam_role.ecs_service.arn}"
19 | }
20 |
21 | output "ecs_service_autoscale_role_arn" {
22 | value = "${aws_iam_role.ecs_service_autoscale.arn}"
23 | }
24 |
--------------------------------------------------------------------------------
/base-infra/modules/security/policies/ecs-instance-policy.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Sid": "ECS",
6 | "Effect": "Allow",
7 | "Action": [
8 | "ecs:CreateCluster",
9 | "ecs:DeregisterContainerInstance",
10 | "ecs:DiscoverPollEndpoint",
11 | "ecs:Poll",
12 | "ecs:RegisterContainerInstance",
13 | "ecs:StartTelemetrySession",
14 | "ecs:Submit*",
15 | "ecs:StartTask",
16 | "ecr:GetAuthorizationToken",
17 | "ecr:BatchCheckLayerAvailability",
18 | "ecr:GetDownloadUrlForLayer",
19 | "ecr:BatchGetImage",
20 | "logs:CreateLogGroup",
21 | "logs:CreateLogStream",
22 | "logs:PutLogEvents",
23 | "logs:DescribeLogStreams"
24 | ],
25 | "Resource": "*"
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/base-infra/modules/security/policies/ecs-instance.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2008-10-17",
3 | "Statement": [
4 | {
5 | "Sid": "EC2",
6 | "Effect": "Allow",
7 | "Principal": {
8 | "Service": "ec2.amazonaws.com"
9 | },
10 | "Action": "sts:AssumeRole"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/base-infra/modules/security/policies/ecs-service-autoscale.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Sid": "Autoscaling",
6 | "Effect": "Allow",
7 | "Principal": {
8 | "Service": "application-autoscaling.amazonaws.com"
9 | },
10 | "Action": "sts:AssumeRole"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/base-infra/modules/security/policies/ecs-service.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2008-10-17",
3 | "Statement": [
4 | {
5 | "Sid": "ECS",
6 | "Effect": "Allow",
7 | "Principal": {
8 | "Service": "ecs.amazonaws.com"
9 | },
10 | "Action": "sts:AssumeRole"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/base-infra/modules/security/variables.tf:
--------------------------------------------------------------------------------
1 | variable "vpc_id" {
2 | description = "Id of VPC where security groups will live"
3 | }
4 |
5 | variable "vpc_cidr_block" {
6 | description = "The source CIDR block to allow traffic from"
7 | }
8 |
9 | variable "ssh_allowed_ip" {
10 | description = "IP address allowed to SSH to bastion instance"
11 | }
12 |
--------------------------------------------------------------------------------
/base-infra/modules/vpc/main.tf:
--------------------------------------------------------------------------------
1 | # VPC
2 | resource "aws_vpc" "vpc" {
3 | cidr_block = "10.0.0.0/16"
4 |
5 | tags {
6 | Name = "vpc"
7 | }
8 | }
9 |
10 | # Internet gateway
11 | resource "aws_internet_gateway" "igw" {
12 | vpc_id = "${aws_vpc.vpc.id}"
13 |
14 | tags {
15 | Name = "igw"
16 | }
17 | }
18 |
19 | # Public subnets
20 | # These will get a 0/0 route to the IGW gateway as below
21 | # The az_count variable determines how many subnets will be created
22 | resource "aws_subnet" "public_subnet" {
23 | count = "${var.az_count}"
24 | vpc_id = "${aws_vpc.vpc.id}"
25 | cidr_block = "10.0.${count.index}.0/24"
26 | availability_zone = "${element(split(",", lookup(var.availability_zones, var.region)), count.index)}"
27 | map_public_ip_on_launch = true
28 |
29 | tags {
30 | Name = "Public-subnet-${count.index + 1}"
31 | }
32 | }
33 |
34 | # Public route table
35 | resource "aws_route_table" "public_rt" {
36 | vpc_id = "${aws_vpc.vpc.id}"
37 |
38 | tags {
39 | Name = "public-rt"
40 | }
41 | }
42 |
43 | # Attach a 0/0 route to the public route table going to the IGW
44 | resource "aws_route" "internet" {
45 | route_table_id = "${aws_route_table.public_rt.id}"
46 | destination_cidr_block = "0.0.0.0/0"
47 | gateway_id = "${aws_internet_gateway.igw.id}"
48 |
49 | depends_on = ["aws_internet_gateway.igw", "aws_route_table.public_rt"]
50 | }
51 |
52 | # Public subnet route table associations
53 | # The az_count variable determines how many associations will be created (one per public subnet)
54 | resource "aws_route_table_association" "public" {
55 | count = "${var.az_count}"
56 | subnet_id = "${element(aws_subnet.public_subnet.*.id, count.index)}"
57 | route_table_id = "${aws_route_table.public_rt.id}"
58 | }
59 |
60 | # The public route needs to be the default one (so that the default
61 | # route on the VPC goes to the IGW).
62 | resource "aws_main_route_table_association" "public" {
63 | vpc_id = "${aws_vpc.vpc.id}"
64 | route_table_id = "${aws_route_table.public_rt.id}"
65 | }
66 |
67 | # NAT gateway elastic IPs
68 | # The az_count variable determines how many EIPs will be created (one per private subnet)
69 | resource "aws_eip" "nat_gateway" {
70 | count = "${var.az_count}"
71 | vpc = true
72 | }
73 |
74 | # NAT gateways
75 | # The az_count variable determines how many NAT gateways will be created (one per public subnet)
76 | resource "aws_nat_gateway" "nat_gateway" {
77 | count = "${var.az_count}"
78 | allocation_id = "${element(aws_eip.nat_gateway.*.id, count.index)}"
79 | subnet_id = "${element(aws_subnet.public_subnet.*.id, count.index)}"
80 | depends_on = ["aws_internet_gateway.igw", "aws_eip.nat_gateway"]
81 | }
82 |
83 | # Private subnets
84 | # The az_count variable determines how many subnets will be created
85 | resource "aws_subnet" "private_subnet" {
86 | count = "${var.az_count}"
87 | vpc_id = "${aws_vpc.vpc.id}"
88 | cidr_block = "10.0.${100 + count.index}.0/24"
89 | availability_zone = "${element(split(",", lookup(var.availability_zones, var.region)), count.index)}"
90 | map_public_ip_on_launch = false
91 |
92 | tags {
93 | Name = "Private-subnet-${count.index + 1}"
94 | }
95 | }
96 |
97 | # Private route tables
98 | # The az_count variable determines how many route tables will be created
99 | # To get around the single-AZ nature of the current NAT Gateway implementation,
100 | # we define a route table per AZ
101 | resource "aws_route_table" "private_rt" {
102 | count = "${var.az_count}"
103 | vpc_id = "${aws_vpc.vpc.id}"
104 |
105 | tags {
106 | Name = "private-rt"
107 | }
108 | }
109 |
110 | # Attach 0/0 route to private route tables going to the NAT gateways
111 | resource "aws_route" "nat" {
112 | count = "${var.az_count}"
113 | route_table_id = "${element(aws_route_table.private_rt.*.id, count.index)}"
114 | destination_cidr_block = "0.0.0.0/0"
115 | nat_gateway_id = "${element(aws_nat_gateway.nat_gateway.*.id, count.index)}"
116 | }
117 |
118 | # Associate the private route tables with the private subnets
119 | resource "aws_route_table_association" "private" {
120 | count = "${var.az_count}"
121 | subnet_id = "${element(aws_subnet.private_subnet.*.id, count.index)}"
122 | route_table_id = "${element(aws_route_table.private_rt.*.id, count.index)}"
123 | }
124 |
--------------------------------------------------------------------------------
/base-infra/modules/vpc/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | value = "${aws_vpc.vpc.id}"
3 | }
4 |
5 | output "vpc_cidr_block" {
6 | value = "${aws_vpc.vpc.cidr_block}"
7 | }
8 |
9 | output "subnet_private_ids" {
10 | value = "${join(",", aws_subnet.private_subnet.*.id)}"
11 | }
12 |
13 | output "subnet_public_ids" {
14 | value = "${join(",", aws_subnet.public_subnet.*.id)}"
15 | }
16 |
--------------------------------------------------------------------------------
/base-infra/modules/vpc/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | description = "AWS region to deploy to (e.g. ap-southeast-2)"
3 | }
4 |
5 | variable "az_count" {
6 | description = "The number of availailbilty zones to deploy across (must be minimum of two to use ALB)"
7 | }
8 |
9 | # Use "aws ec2 describe-availability-zones --region us-east-1"
10 | # to figure out the name of the AZs on every region as required
11 | variable "availability_zones" {
12 | description = "Availability zones by region"
13 | default = {
14 | "ap-southeast-2" = "ap-southeast-2a,ap-southeast-2b,ap-southeast-2c"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/base-infra/outputs.tf:
--------------------------------------------------------------------------------
1 | output "vpc_id" {
2 | value = "${module.vpc.vpc_id}"
3 | }
4 |
5 | output "alb_listener_arn" {
6 | value = "${module.alb.alb_listener_arn}"
7 | }
8 |
9 | output "cluster_name" {
10 | value = "${module.ecs_cluster.cluster_name}"
11 | }
12 |
13 | output "ecs_service_role_arn" {
14 | value = "${module.security.ecs_service_role_arn}"
15 | }
16 |
17 | output "ecs_service_autoscale_role_arn" {
18 | value = "${module.security.ecs_service_autoscale_role_arn}"
19 | }
20 |
--------------------------------------------------------------------------------
/base-infra/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | description = "AWS region to deploy to (e.g. ap-southeast-2)"
3 | }
4 |
5 | variable "az_count" {
6 | description = "The number of availailbilty zones to deploy across (must be minimum of two to use ALB)"
7 | default = 3
8 | }
9 |
10 | variable "ssh_allowed_ip" {
11 | description = "IP address allowed to SSH to bastion instance"
12 | }
13 |
14 | variable "acm_arn" {
15 | description = "ARN of ACM SSL certificate"
16 | }
17 |
18 | variable "route53_zone_id" {
19 | description = "Route 53 Hosted Zone ID"
20 | }
21 |
22 | variable "alb_dns_name" {
23 | description = "DNS name for ALB"
24 | }
25 |
26 | variable "cluster_name" {
27 | description = "Name of the ECS cluster"
28 | }
29 |
30 | variable "datadog_api_key" {
31 | description = "Datadog API key"
32 | }
33 |
34 | variable "instance_type" {
35 | description = "Instance type of each EC2 instance in the ECS cluster"
36 | }
37 |
38 | variable "key_pair_name" {
39 | description = "Name of the Key Pair that can be used to SSH to each EC2 instance in the ECS cluster"
40 | }
41 |
42 | variable "ami" {
43 | description = "AMI of each EC2 instance in the ECS cluster"
44 | # These are ids for Amazon's ECS-Optimized Linux AMI from: http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-optimized_AMI.html
45 | # Note that the very first time, you have to accept the terms and conditions on that page or the EC2 instances will fail to launch!
46 | default = {
47 | us-east-1 = "ami-1924770e"
48 | ap-southeast-2 = "ami-73407d10"
49 | }
50 | }
51 |
52 | variable "asg_min" {
53 | description = "Minimum number of EC2 instances to run in the ECS cluster"
54 | default = 3
55 | }
56 |
57 | variable "asg_max" {
58 | description = "Maximum number of EC2 instances to run in the ECS cluster"
59 | default = 9
60 | }
61 |
62 | variable "bastion_instance_type" {
63 | description = "Instance type of bastion instance (e.g. t2.micro)"
64 | }
65 |
66 | variable "bastion_key_pair_name" {
67 | description = "Name of the Key Pair that can be used to access bastion instance"
68 | }
69 |
70 | variable "bastion_ami" {
71 | description = "AMI of bastion instance"
72 | # These are ids for Amazon's Linux AMI from: https://aws.amazon.com/amazon-linux-ami
73 | default = {
74 | us-east-1 = "ami-b73b63a0"
75 | ap-southeast-2 = "ami-db704cb8"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/beta-service/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2017-node7"]
3 | }
4 |
--------------------------------------------------------------------------------
/beta-service/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 |
--------------------------------------------------------------------------------
/beta-service/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | extends: "airbnb-base",
3 | env: {
4 | node: true,
5 | es6: true
6 | },
7 | parser: "babel-eslint",
8 | rules: {
9 | max-len: ["error", 120, 2]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/beta-service/beta-service.tfvars:
--------------------------------------------------------------------------------
1 | region = "ap-southeast-2"
2 |
3 | service_name = "beta-service"
4 |
5 | container_port = "80"
6 |
7 | docker_image = "jch254/ecs-demo-api"
8 |
9 | docker_tag = "latest"
10 |
--------------------------------------------------------------------------------
/beta-service/deploy.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | cd beta-service
4 |
5 | terraform remote config -backend=s3 \
6 | -backend-config="bucket=603-terraform-remote-state" \
7 | -backend-config="key=terraform-ecs-autoscale-alb/beta-service.tfstate" \
8 | -backend-config="region=ap-southeast-2" \
9 | -backend-config="encrypt=true"
10 |
11 | terraform get --update
12 | terraform plan -var-file beta-service.tfvars
13 | terraform apply -var-file beta-service.tfvars
14 |
15 | cd ..
16 |
--------------------------------------------------------------------------------
/beta-service/modules.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = "${var.region}"
3 | }
4 |
5 | data "terraform_remote_state" "base_remote_state" {
6 | backend = "s3"
7 | config {
8 | bucket = "603-terraform-remote-state"
9 | key = "terraform-ecs-autoscale-alb/base-infra.tfstate"
10 | region = "${var.region}"
11 | }
12 | }
13 |
14 | module "alb_listener" {
15 | source = "./modules/alb-listener"
16 |
17 | service_name = "${var.service_name}"
18 | container_port = "${var.container_port}"
19 | vpc_id = "${data.terraform_remote_state.base_remote_state.vpc_id}"
20 | alb_listener_arn = "${data.terraform_remote_state.base_remote_state.alb_listener_arn}"
21 | }
22 |
23 | module "ecs_service" {
24 | source = "./modules/ecs-service"
25 |
26 | service_name = "${var.service_name}"
27 | docker_image = "${var.docker_image}"
28 | docker_tag = "${var.docker_tag}"
29 | container_cpu = "${var.container_cpu}"
30 | container_memory = "${var.container_memory}"
31 | container_port = "${var.container_port}"
32 | region = "${var.region}"
33 | cluster_name = "${data.terraform_remote_state.base_remote_state.cluster_name}"
34 | desired_count = "${var.min_capacity}"
35 | ecs_service_role_arn = "${data.terraform_remote_state.base_remote_state.ecs_service_role_arn}"
36 | target_group_arn = "${module.alb_listener.target_group_arn}"
37 | }
38 |
39 | module "autoscaling" {
40 | source = "./modules/autoscaling"
41 |
42 | service_name = "${var.service_name}"
43 | cluster_name = "${data.terraform_remote_state.base_remote_state.cluster_name}"
44 | ecs_service_autoscale_role_arn = "${data.terraform_remote_state.base_remote_state.ecs_service_autoscale_role_arn}"
45 | min_capacity = "${var.min_capacity}"
46 | max_capacity = "${var.max_capacity}"
47 | }
48 |
--------------------------------------------------------------------------------
/beta-service/modules/alb-listener/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_alb_target_group" "beta_service_tg" {
2 | name = "${replace(var.service_name, "/(.{0,28})(.*)/", "$1")}-tg"
3 |
4 | protocol = "HTTP"
5 | port = "${var.container_port}"
6 | vpc_id = "${var.vpc_id}"
7 |
8 | health_check {
9 | path = "/ping"
10 | }
11 | }
12 |
13 | resource "aws_alb_listener_rule" "beta_service_listener" {
14 | listener_arn = "${var.alb_listener_arn}"
15 | priority = 200
16 |
17 | action {
18 | type = "forward"
19 | target_group_arn = "${aws_alb_target_group.beta_service_tg.arn}"
20 | }
21 |
22 | condition {
23 | field = "path-pattern"
24 | values = ["/beta/*"]
25 | }
26 |
27 | depends_on = ["aws_alb_target_group.beta_service_tg"]
28 | }
29 |
--------------------------------------------------------------------------------
/beta-service/modules/alb-listener/outputs.tf:
--------------------------------------------------------------------------------
1 | output "target_group_arn" {
2 | value = "${aws_alb_target_group.beta_service_tg.arn}"
3 | }
4 |
--------------------------------------------------------------------------------
/beta-service/modules/alb-listener/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "container_port" {
6 | description = "Port that service will listen on"
7 | }
8 |
9 | variable "vpc_id" {
10 | description = "Id of the VPC where service should be deployed"
11 | }
12 |
13 | variable "alb_listener_arn" {
14 | description = "ARN of ALB listener"
15 | }
16 |
--------------------------------------------------------------------------------
/beta-service/modules/autoscaling/main.tf:
--------------------------------------------------------------------------------
1 | # A CloudWatch alarm that moniors CPU utilization of containers for scaling up
2 | resource "aws_cloudwatch_metric_alarm" "beta_service_cpu_high" {
3 | alarm_name = "${var.service_name}-cpu-utilization-above-80"
4 | alarm_description = "This alarm monitors ${var.service_name} CPU utilization for scaling up"
5 | comparison_operator = "GreaterThanOrEqualToThreshold"
6 | evaluation_periods = "1"
7 | metric_name = "CPUUtilization"
8 | namespace = "AWS/ECS"
9 | period = "120"
10 | statistic = "Average"
11 | threshold = "80"
12 | alarm_actions = ["${aws_appautoscaling_policy.scale_up.arn}"]
13 |
14 | dimensions {
15 | ClusterName = "${var.cluster_name}"
16 | ServiceName = "${var.service_name}"
17 | }
18 | }
19 |
20 | # A CloudWatch alarm that monitors CPU utilization of containers for scaling down
21 | resource "aws_cloudwatch_metric_alarm" "beta_service_cpu_low" {
22 | alarm_name = "${var.service_name}-cpu-utilization-below-5"
23 | alarm_description = "This alarm monitors ${var.service_name} CPU utilization for scaling down"
24 | comparison_operator = "LessThanThreshold"
25 | evaluation_periods = "1"
26 | metric_name = "CPUUtilization"
27 | namespace = "AWS/ECS"
28 | period = "120"
29 | statistic = "Average"
30 | threshold = "5"
31 | alarm_actions = ["${aws_appautoscaling_policy.scale_down.arn}"]
32 |
33 | dimensions {
34 | ClusterName = "${var.cluster_name}"
35 | ServiceName = "${var.service_name}"
36 | }
37 | }
38 |
39 | # A CloudWatch alarm that monitors memory utilization of containers for scaling up
40 | resource "aws_cloudwatch_metric_alarm" "beta_service_memory_high" {
41 | alarm_name = "${var.service_name}-memory-utilization-above-80"
42 | alarm_description = "This alarm monitors ${var.service_name} memory utilization for scaling up"
43 | comparison_operator = "GreaterThanOrEqualToThreshold"
44 | evaluation_periods = "1"
45 | metric_name = "MemoryUtilization"
46 | namespace = "AWS/ECS"
47 | period = "120"
48 | statistic = "Average"
49 | threshold = "80"
50 | alarm_actions = ["${aws_appautoscaling_policy.scale_up.arn}"]
51 |
52 | dimensions {
53 | ClusterName = "${var.cluster_name}"
54 | ServiceName = "${var.service_name}"
55 | }
56 | }
57 |
58 | # A CloudWatch alarm that monitors memory utilization of containers for scaling down
59 | resource "aws_cloudwatch_metric_alarm" "beta_service_memory_low" {
60 | alarm_name = "${var.service_name}-memory-utilization-below-5"
61 | alarm_description = "This alarm monitors ${var.service_name} memory utilization for scaling down"
62 | comparison_operator = "LessThanThreshold"
63 | evaluation_periods = "1"
64 | metric_name = "MemoryUtilization"
65 | namespace = "AWS/ECS"
66 | period = "120"
67 | statistic = "Average"
68 | threshold = "5"
69 | alarm_actions = ["${aws_appautoscaling_policy.scale_down.arn}"]
70 |
71 | dimensions {
72 | ClusterName = "${var.cluster_name}"
73 | ServiceName = "${var.service_name}"
74 | }
75 | }
76 |
77 | resource "aws_appautoscaling_target" "target" {
78 | resource_id = "service/${var.cluster_name}/${var.service_name}"
79 | role_arn = "${var.ecs_service_autoscale_role_arn}"
80 | scalable_dimension = "ecs:service:DesiredCount"
81 | min_capacity = "${var.min_capacity}"
82 | max_capacity = "${var.max_capacity}"
83 | }
84 |
85 | resource "aws_appautoscaling_policy" "scale_up" {
86 | name = "${var.service_name}-scale-up"
87 | resource_id = "service/${var.cluster_name}/${var.service_name}"
88 | scalable_dimension = "ecs:service:DesiredCount"
89 | adjustment_type = "ChangeInCapacity"
90 | cooldown = 120
91 | metric_aggregation_type = "Average"
92 |
93 | step_adjustment {
94 | metric_interval_lower_bound = 0
95 | scaling_adjustment = 1
96 | }
97 |
98 | depends_on = ["aws_appautoscaling_target.target"]
99 | }
100 |
101 | resource "aws_appautoscaling_policy" "scale_down" {
102 | name = "${var.service_name}-scale-down"
103 | resource_id = "service/${var.cluster_name}/${var.service_name}"
104 | scalable_dimension = "ecs:service:DesiredCount"
105 | adjustment_type = "ChangeInCapacity"
106 | cooldown = 120
107 | metric_aggregation_type = "Average"
108 |
109 | step_adjustment {
110 | metric_interval_upper_bound = 0
111 | scaling_adjustment = -1
112 | }
113 |
114 | depends_on = ["aws_appautoscaling_target.target"]
115 | }
116 |
--------------------------------------------------------------------------------
/beta-service/modules/autoscaling/outputs.tf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jch254/terraform-ecs-autoscale-alb/ee36aa5462166922123252be846c338b9bd9f1b6/beta-service/modules/autoscaling/outputs.tf
--------------------------------------------------------------------------------
/beta-service/modules/autoscaling/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "cluster_name" {
6 | description = "Name of ECS cluster"
7 | }
8 |
9 | variable "ecs_service_autoscale_role_arn" {
10 | description = "ARN of IAM role for ECS service autoscaling"
11 | }
12 |
13 | variable "min_capacity" {
14 | description = "Minimum number of containers to run"
15 | }
16 |
17 | variable "max_capacity" {
18 | description = "Minimum number of containers to run"
19 | }
20 |
--------------------------------------------------------------------------------
/beta-service/modules/ecs-service/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_cloudwatch_log_group" "beta_service_lg" {
2 | name = "${var.service_name}"
3 | }
4 |
5 | data "template_file" "task_definition" {
6 | template = "${file("${path.module}/task-definition.json")}"
7 |
8 | vars {
9 | service_name = "${var.service_name}"
10 | docker_image = "${var.docker_image}"
11 | docker_tag = "${var.docker_tag}"
12 | container_cpu = "${var.container_cpu}"
13 | container_memory = "${var.container_memory}"
14 | container_port = "${var.container_port}"
15 | log_group_name = "${aws_cloudwatch_log_group.beta_service_lg.name}"
16 | log_group_region = "${var.region}"
17 | }
18 | }
19 |
20 | # The ECS task that specifies what Docker containers we need to run the service
21 | resource "aws_ecs_task_definition" "beta_service" {
22 | family = "${var.service_name}"
23 | container_definitions = "${data.template_file.task_definition.rendered}"
24 | }
25 |
26 | # A long-running ECS service for the beta_service task
27 | resource "aws_ecs_service" "beta_service" {
28 | name = "${var.service_name}"
29 | cluster = "${var.cluster_name}"
30 | task_definition = "${aws_ecs_task_definition.beta_service.arn}"
31 | desired_count = "${var.desired_count}"
32 | deployment_minimum_healthy_percent = 50
33 | deployment_maximum_percent = 100
34 | iam_role = "${var.ecs_service_role_arn}"
35 |
36 | load_balancer {
37 | target_group_arn = "${var.target_group_arn}"
38 | container_name = "${var.service_name}"
39 | container_port = "${var.container_port}"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/beta-service/modules/ecs-service/outputs.tf:
--------------------------------------------------------------------------------
1 | output "service_name" {
2 | value = "${aws_ecs_service.beta_service.name}"
3 | }
4 |
--------------------------------------------------------------------------------
/beta-service/modules/ecs-service/task-definition.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "${service_name}",
4 | "image": "${docker_image}:${docker_tag}",
5 | "cpu": ${container_cpu},
6 | "memory": ${container_memory},
7 | "essential": true,
8 | "portMappings": [
9 | {
10 | "containerPort": ${container_port}
11 | }
12 | ],
13 | "logConfiguration": {
14 | "logDriver": "awslogs",
15 | "options": {
16 | "awslogs-group": "${log_group_name}",
17 | "awslogs-region": "${log_group_region}"
18 | }
19 | },
20 | "environment": [
21 | { "name": "SERVICE_NAME", "value": "${service_name}"}
22 | ]
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/beta-service/modules/ecs-service/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "docker_image" {
6 | description = "Docker image to run"
7 | }
8 |
9 | variable "docker_tag" {
10 | description = "Tag of docker image to run"
11 | }
12 |
13 | variable "container_cpu" {
14 | description = "The number of cpu units to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
15 | }
16 |
17 | variable "container_memory" {
18 | description = "The number of MiB of memory to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
19 | }
20 |
21 | variable "container_port" {
22 | description = "Port that service will listen on"
23 | }
24 |
25 | variable "region" {
26 | description = "AWS region to deploy to (e.g. ap-southeast-2)"
27 | }
28 |
29 | variable "cluster_name" {
30 | description = "Name of ECS cluster"
31 | }
32 |
33 | variable "desired_count" {
34 | description = "Initial number of containers to run"
35 | }
36 |
37 | variable "ecs_service_role_arn" {
38 | description = "ARN of IAM role for ECS service"
39 | }
40 |
41 | variable "target_group_arn" {
42 | description = "ARN of ALB target group for service"
43 | }
44 |
--------------------------------------------------------------------------------
/beta-service/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | description = "AWS region to deploy to (e.g. ap-southeast-2)"
3 | }
4 |
5 | variable "service_name" {
6 | description = "Name of service"
7 | }
8 |
9 | variable "container_port" {
10 | description = "Port that service will listen on"
11 | }
12 |
13 | variable "docker_image" {
14 | description = "Docker image to run"
15 | }
16 |
17 | variable "docker_tag" {
18 | description = "Tag of docker image to run"
19 | }
20 |
21 | variable "container_cpu" {
22 | description = "The number of cpu units to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
23 | default = "256"
24 | }
25 |
26 | variable "container_memory" {
27 | description = "The number of MiB of memory to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
28 | default = "256"
29 | }
30 |
31 | variable "min_capacity" {
32 | description = "Minimum number of containers to run"
33 | default = 2
34 | }
35 |
36 | variable "max_capacity" {
37 | description = "Minimum number of containers to run"
38 | default = 6
39 | }
40 |
--------------------------------------------------------------------------------
/bitbucket-pipelines.yml:
--------------------------------------------------------------------------------
1 | image: jch254/docker-node-terraform-aws:latest
2 | pipelines:
3 | branches:
4 | master:
5 | - step:
6 | script:
7 | - echo 'Refer to README.md for instructions and then uncomment steps below'
8 | #- ./base-infra/deploy.bash
9 | #- ./alpha-service/deploy.bash
10 | #- ./beta-service/deploy.bash
11 | #- ./charlie-service/deploy.bash
12 |
--------------------------------------------------------------------------------
/charlie-service/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2017-node7"]
3 | }
4 |
--------------------------------------------------------------------------------
/charlie-service/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 |
--------------------------------------------------------------------------------
/charlie-service/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | extends: "airbnb-base",
3 | env: {
4 | node: true,
5 | es6: true
6 | },
7 | parser: "babel-eslint",
8 | rules: {
9 | max-len: ["error", 120, 2]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/charlie-service/charlie-service.tfvars:
--------------------------------------------------------------------------------
1 | region = "ap-southeast-2"
2 |
3 | service_name = "charlie-service"
4 |
5 | container_port = "80"
6 |
7 | docker_image = "jch254/ecs-demo-api"
8 |
9 | docker_tag = "latest"
10 |
--------------------------------------------------------------------------------
/charlie-service/deploy.bash:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | cd charlie-service
4 |
5 | terraform remote config -backend=s3 \
6 | -backend-config="bucket=603-terraform-remote-state" \
7 | -backend-config="key=terraform-ecs-autoscale-alb/charlie-service.tfstate" \
8 | -backend-config="region=ap-southeast-2" \
9 | -backend-config="encrypt=true"
10 |
11 | terraform get --update
12 | terraform plan -var-file charlie-service.tfvars
13 | terraform apply -var-file charlie-service.tfvars
14 |
15 | cd ..
16 |
--------------------------------------------------------------------------------
/charlie-service/modules.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | region = "${var.region}"
3 | }
4 |
5 | data "terraform_remote_state" "base_remote_state" {
6 | backend = "s3"
7 | config {
8 | bucket = "603-terraform-remote-state"
9 | key = "terraform-ecs-autoscale-alb/base-infra.tfstate"
10 | region = "${var.region}"
11 | }
12 | }
13 |
14 | module "alb_listener" {
15 | source = "./modules/alb-listener"
16 |
17 | service_name = "${var.service_name}"
18 | container_port = "${var.container_port}"
19 | vpc_id = "${data.terraform_remote_state.base_remote_state.vpc_id}"
20 | alb_listener_arn = "${data.terraform_remote_state.base_remote_state.alb_listener_arn}"
21 | }
22 |
23 | module "ecs_service" {
24 | source = "./modules/ecs-service"
25 |
26 | service_name = "${var.service_name}"
27 | docker_image = "${var.docker_image}"
28 | docker_tag = "${var.docker_tag}"
29 | container_cpu = "${var.container_cpu}"
30 | container_memory = "${var.container_memory}"
31 | container_port = "${var.container_port}"
32 | region = "${var.region}"
33 | cluster_name = "${data.terraform_remote_state.base_remote_state.cluster_name}"
34 | desired_count = "${var.min_capacity}"
35 | ecs_service_role_arn = "${data.terraform_remote_state.base_remote_state.ecs_service_role_arn}"
36 | target_group_arn = "${module.alb_listener.target_group_arn}"
37 | }
38 |
39 | module "autoscaling" {
40 | source = "./modules/autoscaling"
41 |
42 | service_name = "${var.service_name}"
43 | cluster_name = "${data.terraform_remote_state.base_remote_state.cluster_name}"
44 | ecs_service_autoscale_role_arn = "${data.terraform_remote_state.base_remote_state.ecs_service_autoscale_role_arn}"
45 | min_capacity = "${var.min_capacity}"
46 | max_capacity = "${var.max_capacity}"
47 | }
48 |
--------------------------------------------------------------------------------
/charlie-service/modules/alb-listener/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_alb_target_group" "charlie_service_tg" {
2 | name = "${replace(var.service_name, "/(.{0,28})(.*)/", "$1")}-tg"
3 |
4 | protocol = "HTTP"
5 | port = "${var.container_port}"
6 | vpc_id = "${var.vpc_id}"
7 |
8 | health_check {
9 | path = "/ping"
10 | }
11 | }
12 |
13 | resource "aws_alb_listener_rule" "charlie_service_listener" {
14 | listener_arn = "${var.alb_listener_arn}"
15 | priority = 300
16 |
17 | action {
18 | type = "forward"
19 | target_group_arn = "${aws_alb_target_group.charlie_service_tg.arn}"
20 | }
21 |
22 | condition {
23 | field = "path-pattern"
24 | values = ["/charlie/*"]
25 | }
26 |
27 | depends_on = ["aws_alb_target_group.charlie_service_tg"]
28 | }
29 |
--------------------------------------------------------------------------------
/charlie-service/modules/alb-listener/outputs.tf:
--------------------------------------------------------------------------------
1 | output "target_group_arn" {
2 | value = "${aws_alb_target_group.charlie_service_tg.arn}"
3 | }
4 |
--------------------------------------------------------------------------------
/charlie-service/modules/alb-listener/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "container_port" {
6 | description = "Port that service will listen on"
7 | }
8 |
9 | variable "vpc_id" {
10 | description = "Id of the VPC where service should be deployed"
11 | }
12 |
13 | variable "alb_listener_arn" {
14 | description = "ARN of ALB listener"
15 | }
16 |
--------------------------------------------------------------------------------
/charlie-service/modules/autoscaling/main.tf:
--------------------------------------------------------------------------------
1 | # A CloudWatch alarm that moniors CPU utilization of containers for scaling up
2 | resource "aws_cloudwatch_metric_alarm" "charlie_service_cpu_high" {
3 | alarm_name = "${var.service_name}-cpu-utilization-above-80"
4 | alarm_description = "This alarm monitors ${var.service_name} CPU utilization for scaling up"
5 | comparison_operator = "GreaterThanOrEqualToThreshold"
6 | evaluation_periods = "1"
7 | metric_name = "CPUUtilization"
8 | namespace = "AWS/ECS"
9 | period = "120"
10 | statistic = "Average"
11 | threshold = "80"
12 | alarm_actions = ["${aws_appautoscaling_policy.scale_up.arn}"]
13 |
14 | dimensions {
15 | ClusterName = "${var.cluster_name}"
16 | ServiceName = "${var.service_name}"
17 | }
18 | }
19 |
20 | # A CloudWatch alarm that monitors CPU utilization of containers for scaling down
21 | resource "aws_cloudwatch_metric_alarm" "charlie_service_cpu_low" {
22 | alarm_name = "${var.service_name}-cpu-utilization-below-5"
23 | alarm_description = "This alarm monitors ${var.service_name} CPU utilization for scaling down"
24 | comparison_operator = "LessThanThreshold"
25 | evaluation_periods = "1"
26 | metric_name = "CPUUtilization"
27 | namespace = "AWS/ECS"
28 | period = "120"
29 | statistic = "Average"
30 | threshold = "5"
31 | alarm_actions = ["${aws_appautoscaling_policy.scale_down.arn}"]
32 |
33 | dimensions {
34 | ClusterName = "${var.cluster_name}"
35 | ServiceName = "${var.service_name}"
36 | }
37 | }
38 |
39 | # A CloudWatch alarm that monitors memory utilization of containers for scaling up
40 | resource "aws_cloudwatch_metric_alarm" "charlie_service_memory_high" {
41 | alarm_name = "${var.service_name}-memory-utilization-above-80"
42 | alarm_description = "This alarm monitors ${var.service_name} memory utilization for scaling up"
43 | comparison_operator = "GreaterThanOrEqualToThreshold"
44 | evaluation_periods = "1"
45 | metric_name = "MemoryUtilization"
46 | namespace = "AWS/ECS"
47 | period = "120"
48 | statistic = "Average"
49 | threshold = "80"
50 | alarm_actions = ["${aws_appautoscaling_policy.scale_up.arn}"]
51 |
52 | dimensions {
53 | ClusterName = "${var.cluster_name}"
54 | ServiceName = "${var.service_name}"
55 | }
56 | }
57 |
58 | # A CloudWatch alarm that monitors memory utilization of containers for scaling down
59 | resource "aws_cloudwatch_metric_alarm" "charlie_service_memory_low" {
60 | alarm_name = "${var.service_name}-memory-utilization-below-5"
61 | alarm_description = "This alarm monitors ${var.service_name} memory utilization for scaling down"
62 | comparison_operator = "LessThanThreshold"
63 | evaluation_periods = "1"
64 | metric_name = "MemoryUtilization"
65 | namespace = "AWS/ECS"
66 | period = "120"
67 | statistic = "Average"
68 | threshold = "5"
69 | alarm_actions = ["${aws_appautoscaling_policy.scale_down.arn}"]
70 |
71 | dimensions {
72 | ClusterName = "${var.cluster_name}"
73 | ServiceName = "${var.service_name}"
74 | }
75 | }
76 |
77 | resource "aws_appautoscaling_target" "target" {
78 | resource_id = "service/${var.cluster_name}/${var.service_name}"
79 | role_arn = "${var.ecs_service_autoscale_role_arn}"
80 | scalable_dimension = "ecs:service:DesiredCount"
81 | min_capacity = "${var.min_capacity}"
82 | max_capacity = "${var.max_capacity}"
83 | }
84 |
85 | resource "aws_appautoscaling_policy" "scale_up" {
86 | name = "${var.service_name}-scale-up"
87 | resource_id = "service/${var.cluster_name}/${var.service_name}"
88 | scalable_dimension = "ecs:service:DesiredCount"
89 | adjustment_type = "ChangeInCapacity"
90 | cooldown = 120
91 | metric_aggregation_type = "Average"
92 |
93 | step_adjustment {
94 | metric_interval_lower_bound = 0
95 | scaling_adjustment = 1
96 | }
97 |
98 | depends_on = ["aws_appautoscaling_target.target"]
99 | }
100 |
101 | resource "aws_appautoscaling_policy" "scale_down" {
102 | name = "${var.service_name}-scale-down"
103 | resource_id = "service/${var.cluster_name}/${var.service_name}"
104 | scalable_dimension = "ecs:service:DesiredCount"
105 | adjustment_type = "ChangeInCapacity"
106 | cooldown = 120
107 | metric_aggregation_type = "Average"
108 |
109 | step_adjustment {
110 | metric_interval_upper_bound = 0
111 | scaling_adjustment = -1
112 | }
113 |
114 | depends_on = ["aws_appautoscaling_target.target"]
115 | }
116 |
--------------------------------------------------------------------------------
/charlie-service/modules/autoscaling/outputs.tf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jch254/terraform-ecs-autoscale-alb/ee36aa5462166922123252be846c338b9bd9f1b6/charlie-service/modules/autoscaling/outputs.tf
--------------------------------------------------------------------------------
/charlie-service/modules/autoscaling/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "cluster_name" {
6 | description = "Name of ECS cluster"
7 | }
8 |
9 | variable "ecs_service_autoscale_role_arn" {
10 | description = "ARN of IAM role for ECS service autoscaling"
11 | }
12 |
13 | variable "min_capacity" {
14 | description = "Minimum number of containers to run"
15 | }
16 |
17 | variable "max_capacity" {
18 | description = "Minimum number of containers to run"
19 | }
20 |
--------------------------------------------------------------------------------
/charlie-service/modules/ecs-service/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_cloudwatch_log_group" "charlie_service_lg" {
2 | name = "${var.service_name}"
3 | }
4 |
5 | data "template_file" "task_definition" {
6 | template = "${file("${path.module}/task-definition.json")}"
7 |
8 | vars {
9 | service_name = "${var.service_name}"
10 | docker_image = "${var.docker_image}"
11 | docker_tag = "${var.docker_tag}"
12 | container_cpu = "${var.container_cpu}"
13 | container_memory = "${var.container_memory}"
14 | container_port = "${var.container_port}"
15 | log_group_name = "${aws_cloudwatch_log_group.charlie_service_lg.name}"
16 | log_group_region = "${var.region}"
17 | }
18 | }
19 |
20 | # The ECS task that specifies what Docker containers we need to run the service
21 | resource "aws_ecs_task_definition" "charlie_service" {
22 | family = "${var.service_name}"
23 | container_definitions = "${data.template_file.task_definition.rendered}"
24 | }
25 |
26 | # A long-running ECS service for the charlie_service task
27 | resource "aws_ecs_service" "charlie_service" {
28 | name = "${var.service_name}"
29 | cluster = "${var.cluster_name}"
30 | task_definition = "${aws_ecs_task_definition.charlie_service.arn}"
31 | desired_count = "${var.desired_count}"
32 | deployment_minimum_healthy_percent = 50
33 | deployment_maximum_percent = 100
34 | iam_role = "${var.ecs_service_role_arn}"
35 |
36 | load_balancer {
37 | target_group_arn = "${var.target_group_arn}"
38 | container_name = "${var.service_name}"
39 | container_port = "${var.container_port}"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/charlie-service/modules/ecs-service/outputs.tf:
--------------------------------------------------------------------------------
1 | output "service_name" {
2 | value = "${aws_ecs_service.charlie_service.name}"
3 | }
4 |
--------------------------------------------------------------------------------
/charlie-service/modules/ecs-service/task-definition.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "${service_name}",
4 | "image": "${docker_image}:${docker_tag}",
5 | "cpu": ${container_cpu},
6 | "memory": ${container_memory},
7 | "essential": true,
8 | "portMappings": [
9 | {
10 | "containerPort": ${container_port}
11 | }
12 | ],
13 | "logConfiguration": {
14 | "logDriver": "awslogs",
15 | "options": {
16 | "awslogs-group": "${log_group_name}",
17 | "awslogs-region": "${log_group_region}"
18 | }
19 | },
20 | "environment": [
21 | { "name": "SERVICE_NAME", "value": "${service_name}"}
22 | ]
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/charlie-service/modules/ecs-service/variables.tf:
--------------------------------------------------------------------------------
1 | variable "service_name" {
2 | description = "Name of service"
3 | }
4 |
5 | variable "docker_image" {
6 | description = "Docker image to run"
7 | }
8 |
9 | variable "docker_tag" {
10 | description = "Tag of docker image to run"
11 | }
12 |
13 | variable "container_cpu" {
14 | description = "The number of cpu units to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
15 | }
16 |
17 | variable "container_memory" {
18 | description = "The number of MiB of memory to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
19 | }
20 |
21 | variable "container_port" {
22 | description = "Port that service will listen on"
23 | }
24 |
25 | variable "region" {
26 | description = "AWS region to deploy to (e.g. ap-southeast-2)"
27 | }
28 |
29 | variable "cluster_name" {
30 | description = "Name of ECS cluster"
31 | }
32 |
33 | variable "desired_count" {
34 | description = "Initial number of containers to run"
35 | }
36 |
37 | variable "ecs_service_role_arn" {
38 | description = "ARN of IAM role for ECS service"
39 | }
40 |
41 | variable "target_group_arn" {
42 | description = "ARN of ALB target group for service"
43 | }
44 |
--------------------------------------------------------------------------------
/charlie-service/variables.tf:
--------------------------------------------------------------------------------
1 | variable "region" {
2 | description = "AWS region to deploy to (e.g. ap-southeast-2)"
3 | }
4 |
5 | variable "service_name" {
6 | description = "Name of service"
7 | }
8 |
9 | variable "container_port" {
10 | description = "Port that service will listen on"
11 | }
12 |
13 | variable "docker_image" {
14 | description = "Docker image to run"
15 | }
16 |
17 | variable "docker_tag" {
18 | description = "Tag of docker image to run"
19 | }
20 |
21 | variable "container_cpu" {
22 | description = "The number of cpu units to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
23 | default = "256"
24 | }
25 |
26 | variable "container_memory" {
27 | description = "The number of MiB of memory to reserve for the container. See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html"
28 | default = "256"
29 | }
30 |
31 | variable "min_capacity" {
32 | description = "Minimum number of containers to run"
33 | default = 2
34 | }
35 |
36 | variable "max_capacity" {
37 | description = "Minimum number of containers to run"
38 | default = 6
39 | }
40 |
--------------------------------------------------------------------------------
/demo-api/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2017-node7"]
3 | }
4 |
--------------------------------------------------------------------------------
/demo-api/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 |
--------------------------------------------------------------------------------
/demo-api/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | extends: "airbnb-base",
3 | env: {
4 | node: true,
5 | es6: true
6 | },
7 | parser: "babel-eslint",
8 | rules: {
9 | max-len: ["error", 120, 2],
10 | no-param-reassign: 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/demo-api/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mhart/alpine-node:latest
2 |
3 | RUN apk add --update python ca-certificates
4 |
5 | RUN npm install -g yarn@0.17.3
6 |
7 | WORKDIR /app
8 |
9 | COPY package.json .
10 | COPY yarn.lock .
11 | RUN yarn install
12 |
13 | COPY .babelrc .
14 | COPY src src
15 | RUN yarn run build
16 |
17 | ENV NODE_ENV=production
18 | ENV PORT=80
19 |
20 | EXPOSE ${PORT}/tcp
21 |
22 | ENTRYPOINT ["node", "--harmony", "dist"]
23 |
--------------------------------------------------------------------------------
/demo-api/README.md:
--------------------------------------------------------------------------------
1 | # Demo-api
2 |
3 | Demo API powered by Node.js/Express.
4 |
5 | ## Running development server (with live-reloading)
6 |
7 | 1. Run the following commands in the app's root directory then submit requests to http://localhost:3000
8 |
9 | ```
10 | yarn install
11 | yarn run dev
12 | ```
13 |
14 | ## Running production version in Docker container
15 | 1. Run the following commands in the app's root directory then submit requests to http://localhost:YOUR_CONTAINER_PORT. YOUR_CONTAINER_ID will be returned by the `docker run` command and YOUR_CONTAINER_PORT will be returned by the `docker port` command.
16 |
17 | ```
18 | docker build -t demo-api .
19 | docker run -d -P demo-api
20 | docker port YOUR_CONTAINER_ID
21 | ```
22 |
--------------------------------------------------------------------------------
/demo-api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Crud-service",
3 | "version": "1.0.0",
4 | "description": "ECS demo CRUD service",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "dev": "nodemon -w src --exec \"babel-node src\"",
8 | "build": "babel src -s -D -d dist",
9 | "lint": "eslint src"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/jch254/terraform-ecs-autoscale-alb"
14 | },
15 | "author": "Jordan Hornblow ",
16 | "license": "MIT",
17 | "dependencies": {
18 | "body-parser": "^1.15.2",
19 | "chance": "^1.0.4",
20 | "cors": "^2.8.1",
21 | "express": "^4.14.0",
22 | "express-winston": "^2.0.0",
23 | "helmet": "^3.1.0",
24 | "json-inflector": "^1.1.0",
25 | "winston": "^2.3.0"
26 | },
27 | "devDependencies": {
28 | "babel-cli": "^6.18.0",
29 | "babel-core": "^6.18.2",
30 | "babel-eslint": "^7.1.0",
31 | "babel-preset-es2017-node7": "^0.4.1",
32 | "eslint": "^3.9.1",
33 | "eslint-config-airbnb-base": "9.0.0",
34 | "eslint-plugin-import": "^2.1.0",
35 | "nodemon": "^1.11.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/demo-api/src/healthcheck/index.js:
--------------------------------------------------------------------------------
1 | import { Router } from 'express';
2 |
3 | export default () => {
4 | const api = Router();
5 |
6 | api.get('/ping', (req, res) => {
7 | res.sendStatus(200);
8 | });
9 |
10 | api.get('/healthcheck', (req, res) => {
11 | res.json({ message: 'All good' });
12 | });
13 |
14 | return api;
15 | };
16 |
--------------------------------------------------------------------------------
/demo-api/src/index.js:
--------------------------------------------------------------------------------
1 | import http from 'http';
2 | import express, { Router } from 'express';
3 | import winston from 'winston';
4 |
5 | import middleware from './middleware';
6 | import healthcheck from './healthcheck';
7 | import items from './items';
8 | import { urlRewriter, topLevelErrorHandler } from './utils';
9 |
10 | const app = express();
11 | const api = Router();
12 |
13 | app.server = http.createServer(app);
14 |
15 | if (process.env.NODE_ENV === 'production') {
16 | app.use(urlRewriter);
17 | }
18 |
19 | app.use(api.get('/', (req, res) => {
20 | res.json({ message: `Hello world from ${process.env.SERVICE_NAME || 'demo-api'}` });
21 | }));
22 |
23 | app.use(middleware());
24 | app.use(healthcheck());
25 | app.use(items());
26 | app.use(topLevelErrorHandler);
27 |
28 | app.server.listen(process.env.PORT || 3000);
29 | winston.info(`${process.env.SERVICE_NAME || 'demo-api'} started on port ${process.env.PORT || 3000}`);
30 |
31 | export default app;
32 |
--------------------------------------------------------------------------------
/demo-api/src/items/index.js:
--------------------------------------------------------------------------------
1 | import { Router } from 'express';
2 |
3 | export default () => {
4 | const api = Router();
5 |
6 | api.get('/items', (req, res) => {
7 | res.json({ items: [{ id: 23, name: 'Cheers cobber' }] });
8 | });
9 |
10 | return api;
11 | };
12 |
--------------------------------------------------------------------------------
/demo-api/src/middleware/index.js:
--------------------------------------------------------------------------------
1 | import { Router } from 'express';
2 | import winston from 'winston';
3 | import expressWinston from 'express-winston';
4 | import helmet from 'helmet';
5 | import bodyParser from 'body-parser';
6 | import cors from 'cors';
7 | import inflector from 'json-inflector';
8 |
9 | export default () => {
10 | const api = Router();
11 |
12 | const inflectorOptions = {
13 | request: 'camelize',
14 | response: 'camelizeLower',
15 | };
16 |
17 | api.use(cors());
18 | api.use(helmet());
19 | api.use(bodyParser.json());
20 | api.use(inflector(inflectorOptions));
21 |
22 | winston.remove(winston.transports.Console);
23 | winston.add(winston.transports.Console, { timestamp: true, colorize: true });
24 |
25 | // Log all requests
26 | api.use(expressWinston.logger({
27 | transports: [
28 | new winston.transports.Console({
29 | timestamp: true,
30 | colorize: true,
31 | }),
32 | ],
33 | expressFormat: true,
34 | }));
35 |
36 | return api;
37 | };
38 |
--------------------------------------------------------------------------------
/demo-api/src/utils.js:
--------------------------------------------------------------------------------
1 | import winston from 'winston';
2 |
3 | // Removes load balancer path from URL
4 | const urlRewriter = (req, res, next) => {
5 | if (req.url.match(/\//g).length >= 2) {
6 | const urlParts = req.url.split('/').filter(p => p.length !== 0);
7 |
8 | req.url = `/${urlParts.slice(1).join('/')}`;
9 | }
10 |
11 | next();
12 | };
13 |
14 | const topLevelErrorHandler = (err, req, res, next) => {
15 | if (res.headersSent) {
16 | return next(err);
17 | }
18 |
19 | winston.error(`${err.message}`);
20 |
21 | if (!err.status) {
22 | winston.error(err.stack);
23 | }
24 |
25 | return res.status(err.status || 500).json({ message: err.responseMessage || 'Matrix glitch' });
26 | };
27 |
28 | const createErrorResponse = (message, statusCode) => {
29 | const err = new Error(message);
30 |
31 | err.responseMessage = message;
32 | err.status = statusCode;
33 |
34 | return err;
35 | };
36 |
37 |
38 | export { urlRewriter, topLevelErrorHandler, createErrorResponse };
39 |
--------------------------------------------------------------------------------
/demo-api/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 | abbrev@1:
4 | version "1.0.9"
5 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
6 |
7 | accepts@~1.3.3:
8 | version "1.3.3"
9 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
10 | dependencies:
11 | mime-types "~2.1.11"
12 | negotiator "0.6.1"
13 |
14 | acorn-jsx@^3.0.0:
15 | version "3.0.1"
16 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
17 | dependencies:
18 | acorn "^3.0.4"
19 |
20 | acorn@^3.0.4:
21 | version "3.3.0"
22 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
23 |
24 | acorn@^4.0.1:
25 | version "4.0.3"
26 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.3.tgz#1a3e850b428e73ba6b09d1cc527f5aaad4d03ef1"
27 |
28 | ajv-keywords@^1.0.0:
29 | version "1.1.1"
30 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.1.1.tgz#02550bc605a3e576041565628af972e06c549d50"
31 |
32 | ajv@^4.7.0:
33 | version "4.8.2"
34 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.8.2.tgz#65486936ca36fea39a1504332a78bebd5d447bdc"
35 | dependencies:
36 | co "^4.6.0"
37 | json-stable-stringify "^1.0.1"
38 |
39 | ansi-escapes@^1.1.0:
40 | version "1.4.0"
41 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
42 |
43 | ansi-regex@^2.0.0:
44 | version "2.0.0"
45 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107"
46 |
47 | ansi-styles@^2.2.1:
48 | version "2.2.1"
49 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
50 |
51 | ansi-styles@~1.0.0:
52 | version "1.0.0"
53 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
54 |
55 | anymatch@^1.3.0:
56 | version "1.3.0"
57 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507"
58 | dependencies:
59 | arrify "^1.0.0"
60 | micromatch "^2.1.5"
61 |
62 | aproba@^1.0.3:
63 | version "1.0.4"
64 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0"
65 |
66 | are-we-there-yet@~1.1.2:
67 | version "1.1.2"
68 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3"
69 | dependencies:
70 | delegates "^1.0.0"
71 | readable-stream "^2.0.0 || ^1.1.13"
72 |
73 | argparse@^1.0.7:
74 | version "1.0.9"
75 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
76 | dependencies:
77 | sprintf-js "~1.0.2"
78 |
79 | arr-diff@^2.0.0:
80 | version "2.0.0"
81 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
82 | dependencies:
83 | arr-flatten "^1.0.1"
84 |
85 | arr-flatten@^1.0.1:
86 | version "1.0.1"
87 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
88 |
89 | array-flatten@1.1.1:
90 | version "1.1.1"
91 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
92 |
93 | array-union@^1.0.1:
94 | version "1.0.2"
95 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
96 | dependencies:
97 | array-uniq "^1.0.1"
98 |
99 | array-uniq@^1.0.1:
100 | version "1.0.3"
101 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
102 |
103 | array-unique@^0.2.1:
104 | version "0.2.1"
105 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
106 |
107 | arrify@^1.0.0:
108 | version "1.0.1"
109 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
110 |
111 | asn1@~0.2.3:
112 | version "0.2.3"
113 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86"
114 |
115 | assert-plus@^0.2.0:
116 | version "0.2.0"
117 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
118 |
119 | assert-plus@^1.0.0:
120 | version "1.0.0"
121 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
122 |
123 | async-each@^1.0.0:
124 | version "1.0.1"
125 | resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d"
126 |
127 | async@~1.0.0:
128 | version "1.0.0"
129 | resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9"
130 |
131 | asynckit@^0.4.0:
132 | version "0.4.0"
133 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
134 |
135 | aws-sign2@~0.6.0:
136 | version "0.6.0"
137 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
138 |
139 | aws4@^1.2.1:
140 | version "1.5.0"
141 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
142 |
143 | babel-cli@^6.18.0:
144 | version "6.18.0"
145 | resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.18.0.tgz#92117f341add9dead90f6fa7d0a97c0cc08ec186"
146 | dependencies:
147 | babel-core "^6.18.0"
148 | babel-polyfill "^6.16.0"
149 | babel-register "^6.18.0"
150 | babel-runtime "^6.9.0"
151 | commander "^2.8.1"
152 | convert-source-map "^1.1.0"
153 | fs-readdir-recursive "^1.0.0"
154 | glob "^5.0.5"
155 | lodash "^4.2.0"
156 | output-file-sync "^1.1.0"
157 | path-is-absolute "^1.0.0"
158 | slash "^1.0.0"
159 | source-map "^0.5.0"
160 | v8flags "^2.0.10"
161 | optionalDependencies:
162 | chokidar "^1.0.0"
163 |
164 | babel-code-frame@^6.16.0:
165 | version "6.16.0"
166 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de"
167 | dependencies:
168 | chalk "^1.1.0"
169 | esutils "^2.0.2"
170 | js-tokens "^2.0.0"
171 |
172 | babel-core@^6.18.0, babel-core@^6.18.2:
173 | version "6.18.2"
174 | resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.18.2.tgz#d8bb14dd6986fa4f3566a26ceda3964fa0e04e5b"
175 | dependencies:
176 | babel-code-frame "^6.16.0"
177 | babel-generator "^6.18.0"
178 | babel-helpers "^6.16.0"
179 | babel-messages "^6.8.0"
180 | babel-register "^6.18.0"
181 | babel-runtime "^6.9.1"
182 | babel-template "^6.16.0"
183 | babel-traverse "^6.18.0"
184 | babel-types "^6.18.0"
185 | babylon "^6.11.0"
186 | convert-source-map "^1.1.0"
187 | debug "^2.1.1"
188 | json5 "^0.5.0"
189 | lodash "^4.2.0"
190 | minimatch "^3.0.2"
191 | path-is-absolute "^1.0.0"
192 | private "^0.1.6"
193 | slash "^1.0.0"
194 | source-map "^0.5.0"
195 |
196 | babel-eslint@^7.1.0:
197 | version "7.1.0"
198 | resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.1.0.tgz#d506a5174ba224e25a2d17e128e2ba8987139ddc"
199 | dependencies:
200 | babel-traverse "^6.15.0"
201 | babel-types "^6.15.0"
202 | babylon "^6.11.2"
203 | lodash.pickby "^4.6.0"
204 |
205 | babel-generator@^6.18.0:
206 | version "6.18.0"
207 | resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.18.0.tgz#e4f104cb3063996d9850556a45aae4a022060a07"
208 | dependencies:
209 | babel-messages "^6.8.0"
210 | babel-runtime "^6.9.0"
211 | babel-types "^6.18.0"
212 | detect-indent "^4.0.0"
213 | jsesc "^1.3.0"
214 | lodash "^4.2.0"
215 | source-map "^0.5.0"
216 |
217 | babel-helper-function-name@^6.18.0:
218 | version "6.18.0"
219 | resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.18.0.tgz#68ec71aeba1f3e28b2a6f0730190b754a9bf30e6"
220 | dependencies:
221 | babel-helper-get-function-arity "^6.18.0"
222 | babel-runtime "^6.0.0"
223 | babel-template "^6.8.0"
224 | babel-traverse "^6.18.0"
225 | babel-types "^6.18.0"
226 |
227 | babel-helper-get-function-arity@^6.18.0:
228 | version "6.18.0"
229 | resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.18.0.tgz#a5b19695fd3f9cdfc328398b47dafcd7094f9f24"
230 | dependencies:
231 | babel-runtime "^6.0.0"
232 | babel-types "^6.18.0"
233 |
234 | babel-helpers@^6.16.0:
235 | version "6.16.0"
236 | resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.16.0.tgz#1095ec10d99279460553e67eb3eee9973d3867e3"
237 | dependencies:
238 | babel-runtime "^6.0.0"
239 | babel-template "^6.16.0"
240 |
241 | babel-messages@^6.8.0:
242 | version "6.8.0"
243 | resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9"
244 | dependencies:
245 | babel-runtime "^6.0.0"
246 |
247 | babel-plugin-syntax-class-properties@^6.8.0:
248 | version "6.13.0"
249 | resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
250 |
251 | babel-plugin-syntax-object-rest-spread@^6.8.0:
252 | version "6.13.0"
253 | resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
254 |
255 | babel-plugin-syntax-trailing-function-commas@^6.13.0:
256 | version "6.13.0"
257 | resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.13.0.tgz#2b84b7d53dd744f94ff1fad7669406274b23f541"
258 |
259 | babel-plugin-transform-class-properties@^6.18.0:
260 | version "6.18.0"
261 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.18.0.tgz#bc1266a39d4c8726e0bd7b15c56235177e6ede57"
262 | dependencies:
263 | babel-helper-function-name "^6.18.0"
264 | babel-plugin-syntax-class-properties "^6.8.0"
265 | babel-runtime "^6.9.1"
266 |
267 | babel-plugin-transform-es2015-modules-commonjs@^6.18.0:
268 | version "6.18.0"
269 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.18.0.tgz#c15ae5bb11b32a0abdcc98a5837baa4ee8d67bcc"
270 | dependencies:
271 | babel-plugin-transform-strict-mode "^6.18.0"
272 | babel-runtime "^6.0.0"
273 | babel-template "^6.16.0"
274 | babel-types "^6.18.0"
275 |
276 | babel-plugin-transform-object-rest-spread@^6.16.0:
277 | version "6.16.0"
278 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.16.0.tgz#db441d56fffc1999052fdebe2e2f25ebd28e36a9"
279 | dependencies:
280 | babel-plugin-syntax-object-rest-spread "^6.8.0"
281 | babel-runtime "^6.0.0"
282 |
283 | babel-plugin-transform-strict-mode@^6.18.0:
284 | version "6.18.0"
285 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.18.0.tgz#df7cf2991fe046f44163dcd110d5ca43bc652b9d"
286 | dependencies:
287 | babel-runtime "^6.0.0"
288 | babel-types "^6.18.0"
289 |
290 | babel-polyfill@^6.16.0:
291 | version "6.16.0"
292 | resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.16.0.tgz#2d45021df87e26a374b6d4d1a9c65964d17f2422"
293 | dependencies:
294 | babel-runtime "^6.9.1"
295 | core-js "^2.4.0"
296 | regenerator-runtime "^0.9.5"
297 |
298 | babel-preset-es2017-node7@^0.4.1:
299 | version "0.4.1"
300 | resolved "https://registry.yarnpkg.com/babel-preset-es2017-node7/-/babel-preset-es2017-node7-0.4.1.tgz#df557eafe343bbc0b859ac3163fdfb0cf58108e5"
301 | dependencies:
302 | babel-plugin-syntax-trailing-function-commas "^6.13.0"
303 | babel-plugin-transform-class-properties "^6.18.0"
304 | babel-plugin-transform-es2015-modules-commonjs "^6.18.0"
305 | babel-plugin-transform-object-rest-spread "^6.16.0"
306 |
307 | babel-register@^6.18.0:
308 | version "6.18.0"
309 | resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.18.0.tgz#892e2e03865078dd90ad2c715111ec4449b32a68"
310 | dependencies:
311 | babel-core "^6.18.0"
312 | babel-runtime "^6.11.6"
313 | core-js "^2.4.0"
314 | home-or-tmp "^2.0.0"
315 | lodash "^4.2.0"
316 | mkdirp "^0.5.1"
317 | source-map-support "^0.4.2"
318 |
319 | babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.9.0, babel-runtime@^6.9.1:
320 | version "6.18.0"
321 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.18.0.tgz#0f4177ffd98492ef13b9f823e9994a02584c9078"
322 | dependencies:
323 | core-js "^2.4.0"
324 | regenerator-runtime "^0.9.5"
325 |
326 | babel-template@^6.16.0, babel-template@^6.8.0:
327 | version "6.16.0"
328 | resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca"
329 | dependencies:
330 | babel-runtime "^6.9.0"
331 | babel-traverse "^6.16.0"
332 | babel-types "^6.16.0"
333 | babylon "^6.11.0"
334 | lodash "^4.2.0"
335 |
336 | babel-traverse@^6.15.0, babel-traverse@^6.16.0, babel-traverse@^6.18.0:
337 | version "6.18.0"
338 | resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.18.0.tgz#5aeaa980baed2a07c8c47329cd90c3b90c80f05e"
339 | dependencies:
340 | babel-code-frame "^6.16.0"
341 | babel-messages "^6.8.0"
342 | babel-runtime "^6.9.0"
343 | babel-types "^6.18.0"
344 | babylon "^6.11.0"
345 | debug "^2.2.0"
346 | globals "^9.0.0"
347 | invariant "^2.2.0"
348 | lodash "^4.2.0"
349 |
350 | babel-types@^6.15.0, babel-types@^6.16.0, babel-types@^6.18.0:
351 | version "6.18.0"
352 | resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.18.0.tgz#1f7d5a73474c59eb9151b2417bbff4e4fce7c3f8"
353 | dependencies:
354 | babel-runtime "^6.9.1"
355 | esutils "^2.0.2"
356 | lodash "^4.2.0"
357 | to-fast-properties "^1.0.1"
358 |
359 | babylon@^6.11.0, babylon@^6.11.2:
360 | version "6.13.1"
361 | resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.13.1.tgz#adca350e088f0467647157652bafead6ddb8dfdb"
362 |
363 | balanced-match@^0.4.1:
364 | version "0.4.2"
365 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
366 |
367 | bcrypt-pbkdf@^1.0.0:
368 | version "1.0.0"
369 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4"
370 | dependencies:
371 | tweetnacl "^0.14.3"
372 |
373 | binary-extensions@^1.0.0:
374 | version "1.7.0"
375 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.7.0.tgz#6c1610db163abfb34edfe42fa423343a1e01185d"
376 |
377 | block-stream@*:
378 | version "0.0.9"
379 | resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
380 | dependencies:
381 | inherits "~2.0.0"
382 |
383 | body-parser@^1.15.2:
384 | version "1.15.2"
385 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.15.2.tgz#d7578cf4f1d11d5f6ea804cef35dc7a7ff6dae67"
386 | dependencies:
387 | bytes "2.4.0"
388 | content-type "~1.0.2"
389 | debug "~2.2.0"
390 | depd "~1.1.0"
391 | http-errors "~1.5.0"
392 | iconv-lite "0.4.13"
393 | on-finished "~2.3.0"
394 | qs "6.2.0"
395 | raw-body "~2.1.7"
396 | type-is "~1.6.13"
397 |
398 | boom@2.x.x:
399 | version "2.10.1"
400 | resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f"
401 | dependencies:
402 | hoek "2.x.x"
403 |
404 | brace-expansion@^1.0.0:
405 | version "1.1.6"
406 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
407 | dependencies:
408 | balanced-match "^0.4.1"
409 | concat-map "0.0.1"
410 |
411 | braces@^1.8.2:
412 | version "1.8.5"
413 | resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
414 | dependencies:
415 | expand-range "^1.8.1"
416 | preserve "^0.2.0"
417 | repeat-element "^1.1.2"
418 |
419 | buffer-shims@^1.0.0:
420 | version "1.0.0"
421 | resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
422 |
423 | builtin-modules@^1.1.1:
424 | version "1.1.1"
425 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
426 |
427 | bytes@2.4.0:
428 | version "2.4.0"
429 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339"
430 |
431 | caller-path@^0.1.0:
432 | version "0.1.0"
433 | resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
434 | dependencies:
435 | callsites "^0.2.0"
436 |
437 | callsites@^0.2.0:
438 | version "0.2.0"
439 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
440 |
441 | camelize@1.0.0:
442 | version "1.0.0"
443 | resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
444 |
445 | caseless@~0.11.0:
446 | version "0.11.0"
447 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
448 |
449 | chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
450 | version "1.1.3"
451 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
452 | dependencies:
453 | ansi-styles "^2.2.1"
454 | escape-string-regexp "^1.0.2"
455 | has-ansi "^2.0.0"
456 | strip-ansi "^3.0.0"
457 | supports-color "^2.0.0"
458 |
459 | chalk@~0.4.0:
460 | version "0.4.0"
461 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
462 | dependencies:
463 | ansi-styles "~1.0.0"
464 | has-color "~0.1.0"
465 | strip-ansi "~0.1.0"
466 |
467 | chance@^1.0.4:
468 | version "1.0.4"
469 | resolved "https://registry.yarnpkg.com/chance/-/chance-1.0.4.tgz#2dbc3ea6ad0541f7f965bd0af25d1ca275c853c4"
470 |
471 | chokidar@^1.0.0, chokidar@^1.4.3:
472 | version "1.6.1"
473 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2"
474 | dependencies:
475 | anymatch "^1.3.0"
476 | async-each "^1.0.0"
477 | glob-parent "^2.0.0"
478 | inherits "^2.0.1"
479 | is-binary-path "^1.0.0"
480 | is-glob "^2.0.0"
481 | path-is-absolute "^1.0.0"
482 | readdirp "^2.0.0"
483 | optionalDependencies:
484 | fsevents "^1.0.0"
485 |
486 | circular-json@^0.3.0:
487 | version "0.3.1"
488 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d"
489 |
490 | cli-cursor@^1.0.1:
491 | version "1.0.2"
492 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
493 | dependencies:
494 | restore-cursor "^1.0.1"
495 |
496 | cli-width@^2.0.0:
497 | version "2.1.0"
498 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a"
499 |
500 | co@^4.6.0:
501 | version "4.6.0"
502 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
503 |
504 | code-point-at@^1.0.0:
505 | version "1.1.0"
506 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
507 |
508 | colors@1.0.x:
509 | version "1.0.3"
510 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
511 |
512 | combined-stream@^1.0.5, combined-stream@~1.0.5:
513 | version "1.0.5"
514 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
515 | dependencies:
516 | delayed-stream "~1.0.0"
517 |
518 | commander@^2.8.1, commander@^2.9.0:
519 | version "2.9.0"
520 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
521 | dependencies:
522 | graceful-readlink ">= 1.0.0"
523 |
524 | concat-map@0.0.1:
525 | version "0.0.1"
526 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
527 |
528 | concat-stream@^1.4.6:
529 | version "1.5.2"
530 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
531 | dependencies:
532 | inherits "~2.0.1"
533 | readable-stream "~2.0.0"
534 | typedarray "~0.0.5"
535 |
536 | configstore@^1.0.0:
537 | version "1.4.0"
538 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021"
539 | dependencies:
540 | graceful-fs "^4.1.2"
541 | mkdirp "^0.5.0"
542 | object-assign "^4.0.1"
543 | os-tmpdir "^1.0.0"
544 | osenv "^0.1.0"
545 | uuid "^2.0.1"
546 | write-file-atomic "^1.1.2"
547 | xdg-basedir "^2.0.0"
548 |
549 | connect@3.4.1:
550 | version "3.4.1"
551 | resolved "https://registry.yarnpkg.com/connect/-/connect-3.4.1.tgz#a21361d3f4099ef761cda6dc4a973bb1ebb0a34d"
552 | dependencies:
553 | debug "~2.2.0"
554 | finalhandler "0.4.1"
555 | parseurl "~1.3.1"
556 | utils-merge "1.0.0"
557 |
558 | console-control-strings@^1.0.0, console-control-strings@~1.1.0:
559 | version "1.1.0"
560 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
561 |
562 | contains-path@^0.1.0:
563 | version "0.1.0"
564 | resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
565 |
566 | content-disposition@0.5.1:
567 | version "0.5.1"
568 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b"
569 |
570 | content-security-policy-builder@1.1.0:
571 | version "1.1.0"
572 | resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-1.1.0.tgz#d91f1b076236c119850c7dee9924bf55e05772b3"
573 | dependencies:
574 | dashify "^0.2.0"
575 |
576 | content-type@~1.0.2:
577 | version "1.0.2"
578 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed"
579 |
580 | convert-source-map@^1.1.0:
581 | version "1.3.0"
582 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67"
583 |
584 | cookie-signature@1.0.6:
585 | version "1.0.6"
586 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
587 |
588 | cookie@0.3.1:
589 | version "0.3.1"
590 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
591 |
592 | core-js@^2.4.0:
593 | version "2.4.1"
594 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
595 |
596 | core-util-is@~1.0.0, core-util-is@1.0.2:
597 | version "1.0.2"
598 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
599 |
600 | cors@^2.8.1:
601 | version "2.8.1"
602 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.1.tgz#6181aa56abb45a2825be3304703747ae4e9d2383"
603 | dependencies:
604 | vary "^1"
605 |
606 | cryptiles@2.x.x:
607 | version "2.0.5"
608 | resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
609 | dependencies:
610 | boom "2.x.x"
611 |
612 | cycle@1.0.x:
613 | version "1.0.3"
614 | resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2"
615 |
616 | d@^0.1.1, d@~0.1.1:
617 | version "0.1.1"
618 | resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309"
619 | dependencies:
620 | es5-ext "~0.10.2"
621 |
622 | dashdash@^1.12.0:
623 | version "1.14.0"
624 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.0.tgz#29e486c5418bf0f356034a993d51686a33e84141"
625 | dependencies:
626 | assert-plus "^1.0.0"
627 |
628 | dasherize@2.0.0:
629 | version "2.0.0"
630 | resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308"
631 |
632 | dashify@^0.2.0:
633 | version "0.2.2"
634 | resolved "https://registry.yarnpkg.com/dashify/-/dashify-0.2.2.tgz#6a07415a01c91faf4a32e38d9dfba71f61cb20fe"
635 |
636 | debug@^2.1.1, debug@^2.2.0, debug@~2.2.0, debug@2.2.0:
637 | version "2.2.0"
638 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
639 | dependencies:
640 | ms "0.7.1"
641 |
642 | deep-extend@~0.4.0:
643 | version "0.4.1"
644 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253"
645 |
646 | deep-is@~0.1.3:
647 | version "0.1.3"
648 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
649 |
650 | del@^2.0.2:
651 | version "2.2.2"
652 | resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
653 | dependencies:
654 | globby "^5.0.0"
655 | is-path-cwd "^1.0.0"
656 | is-path-in-cwd "^1.0.0"
657 | object-assign "^4.0.1"
658 | pify "^2.0.0"
659 | pinkie-promise "^2.0.0"
660 | rimraf "^2.2.8"
661 |
662 | delayed-stream@~1.0.0:
663 | version "1.0.0"
664 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
665 |
666 | delegates@^1.0.0:
667 | version "1.0.0"
668 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
669 |
670 | depd@~1.1.0:
671 | version "1.1.0"
672 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3"
673 |
674 | destroy@~1.0.4:
675 | version "1.0.4"
676 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
677 |
678 | detect-indent@^4.0.0:
679 | version "4.0.0"
680 | resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
681 | dependencies:
682 | repeating "^2.0.0"
683 |
684 | dns-prefetch-control@0.1.0:
685 | version "0.1.0"
686 | resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2"
687 |
688 | doctrine@^1.2.2, doctrine@1.5.0:
689 | version "1.5.0"
690 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
691 | dependencies:
692 | esutils "^2.0.2"
693 | isarray "^1.0.0"
694 |
695 | dont-sniff-mimetype@1.0.0:
696 | version "1.0.0"
697 | resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58"
698 |
699 | duplexer@~0.1.1:
700 | version "0.1.1"
701 | resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
702 |
703 | duplexify@^3.2.0:
704 | version "3.5.0"
705 | resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.0.tgz#1aa773002e1578457e9d9d4a50b0ccaaebcbd604"
706 | dependencies:
707 | end-of-stream "1.0.0"
708 | inherits "^2.0.1"
709 | readable-stream "^2.0.0"
710 | stream-shift "^1.0.0"
711 |
712 | ecc-jsbn@~0.1.1:
713 | version "0.1.1"
714 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
715 | dependencies:
716 | jsbn "~0.1.0"
717 |
718 | ee-first@1.1.1:
719 | version "1.1.1"
720 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
721 |
722 | encodeurl@~1.0.1:
723 | version "1.0.1"
724 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
725 |
726 | end-of-stream@1.0.0:
727 | version "1.0.0"
728 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.0.0.tgz#d4596e702734a93e40e9af864319eabd99ff2f0e"
729 | dependencies:
730 | once "~1.3.0"
731 |
732 | es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7:
733 | version "0.10.12"
734 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047"
735 | dependencies:
736 | es6-iterator "2"
737 | es6-symbol "~3.1"
738 |
739 | es6-iterator@2:
740 | version "2.0.0"
741 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac"
742 | dependencies:
743 | d "^0.1.1"
744 | es5-ext "^0.10.7"
745 | es6-symbol "3"
746 |
747 | es6-map@^0.1.3:
748 | version "0.1.4"
749 | resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897"
750 | dependencies:
751 | d "~0.1.1"
752 | es5-ext "~0.10.11"
753 | es6-iterator "2"
754 | es6-set "~0.1.3"
755 | es6-symbol "~3.1.0"
756 | event-emitter "~0.3.4"
757 |
758 | es6-promise@^3.0.2:
759 | version "3.3.1"
760 | resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"
761 |
762 | es6-set@~0.1.3:
763 | version "0.1.4"
764 | resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8"
765 | dependencies:
766 | d "~0.1.1"
767 | es5-ext "~0.10.11"
768 | es6-iterator "2"
769 | es6-symbol "3"
770 | event-emitter "~0.3.4"
771 |
772 | es6-symbol@~3.1, es6-symbol@~3.1.0, es6-symbol@3:
773 | version "3.1.0"
774 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa"
775 | dependencies:
776 | d "~0.1.1"
777 | es5-ext "~0.10.11"
778 |
779 | es6-weak-map@^2.0.1:
780 | version "2.0.1"
781 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81"
782 | dependencies:
783 | d "^0.1.1"
784 | es5-ext "^0.10.8"
785 | es6-iterator "2"
786 | es6-symbol "3"
787 |
788 | escape-html@~1.0.3:
789 | version "1.0.3"
790 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
791 |
792 | escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
793 | version "1.0.5"
794 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
795 |
796 | escope@^3.6.0:
797 | version "3.6.0"
798 | resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
799 | dependencies:
800 | es6-map "^0.1.3"
801 | es6-weak-map "^2.0.1"
802 | esrecurse "^4.1.0"
803 | estraverse "^4.1.1"
804 |
805 | eslint-config-airbnb-base@9.0.0:
806 | version "9.0.0"
807 | resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-9.0.0.tgz#03e135562aa6c4d0d9f1bbda96d901326bf58ad2"
808 |
809 | eslint-import-resolver-node@^0.2.0:
810 | version "0.2.3"
811 | resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c"
812 | dependencies:
813 | debug "^2.2.0"
814 | object-assign "^4.0.1"
815 | resolve "^1.1.6"
816 |
817 | eslint-module-utils@^1.0.0:
818 | version "1.0.0"
819 | resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-1.0.0.tgz#c4a57fd3a53efd8426cc2d5550aadab9bbd05fd0"
820 | dependencies:
821 | debug "2.2.0"
822 | pkg-dir "^1.0.0"
823 |
824 | eslint-plugin-import@^2.1.0:
825 | version "2.1.0"
826 | resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.1.0.tgz#20fe254aa7dac0d9fe617979f14b59f0f762e1b4"
827 | dependencies:
828 | builtin-modules "^1.1.1"
829 | contains-path "^0.1.0"
830 | debug "^2.2.0"
831 | doctrine "1.5.0"
832 | eslint-import-resolver-node "^0.2.0"
833 | eslint-module-utils "^1.0.0"
834 | has "^1.0.1"
835 | lodash.cond "^4.3.0"
836 | minimatch "^3.0.3"
837 | pkg-up "^1.0.0"
838 |
839 | eslint@^3.9.1:
840 | version "3.9.1"
841 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.9.1.tgz#5a8597706fc6048bc6061ac754d4a211d28f4f5b"
842 | dependencies:
843 | babel-code-frame "^6.16.0"
844 | chalk "^1.1.3"
845 | concat-stream "^1.4.6"
846 | debug "^2.1.1"
847 | doctrine "^1.2.2"
848 | escope "^3.6.0"
849 | espree "^3.3.1"
850 | estraverse "^4.2.0"
851 | esutils "^2.0.2"
852 | file-entry-cache "^2.0.0"
853 | glob "^7.0.3"
854 | globals "^9.2.0"
855 | ignore "^3.1.5"
856 | imurmurhash "^0.1.4"
857 | inquirer "^0.12.0"
858 | is-my-json-valid "^2.10.0"
859 | is-resolvable "^1.0.0"
860 | js-yaml "^3.5.1"
861 | json-stable-stringify "^1.0.0"
862 | levn "^0.3.0"
863 | lodash "^4.0.0"
864 | mkdirp "^0.5.0"
865 | natural-compare "^1.4.0"
866 | optionator "^0.8.2"
867 | path-is-inside "^1.0.1"
868 | pluralize "^1.2.1"
869 | progress "^1.1.8"
870 | require-uncached "^1.0.2"
871 | shelljs "^0.7.5"
872 | strip-bom "^3.0.0"
873 | strip-json-comments "~1.0.1"
874 | table "^3.7.8"
875 | text-table "~0.2.0"
876 | user-home "^2.0.0"
877 |
878 | espree@^3.3.1:
879 | version "3.3.2"
880 | resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c"
881 | dependencies:
882 | acorn "^4.0.1"
883 | acorn-jsx "^3.0.0"
884 |
885 | esprima@^2.6.0:
886 | version "2.7.3"
887 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
888 |
889 | esrecurse@^4.1.0:
890 | version "4.1.0"
891 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220"
892 | dependencies:
893 | estraverse "~4.1.0"
894 | object-assign "^4.0.1"
895 |
896 | estraverse@^4.1.1, estraverse@^4.2.0:
897 | version "4.2.0"
898 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
899 |
900 | estraverse@~4.1.0:
901 | version "4.1.1"
902 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2"
903 |
904 | esutils@^2.0.2:
905 | version "2.0.2"
906 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
907 |
908 | etag@~1.7.0:
909 | version "1.7.0"
910 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8"
911 |
912 | event-emitter@~0.3.4:
913 | version "0.3.4"
914 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5"
915 | dependencies:
916 | d "~0.1.1"
917 | es5-ext "~0.10.7"
918 |
919 | event-stream@~3.3.0:
920 | version "3.3.4"
921 | resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571"
922 | dependencies:
923 | duplexer "~0.1.1"
924 | from "~0"
925 | map-stream "~0.1.0"
926 | pause-stream "0.0.11"
927 | split "0.3"
928 | stream-combiner "~0.0.4"
929 | through "~2.3.1"
930 |
931 | exit-hook@^1.0.0:
932 | version "1.1.1"
933 | resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
934 |
935 | expand-brackets@^0.1.4:
936 | version "0.1.5"
937 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
938 | dependencies:
939 | is-posix-bracket "^0.1.0"
940 |
941 | expand-range@^1.8.1:
942 | version "1.8.2"
943 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
944 | dependencies:
945 | fill-range "^2.1.0"
946 |
947 | express-winston@^2.0.0:
948 | version "2.0.0"
949 | resolved "https://registry.yarnpkg.com/express-winston/-/express-winston-2.0.0.tgz#1100eda7e7f7a8f7c20a1ce1fa45de22168552b8"
950 | dependencies:
951 | chalk "~0.4.0"
952 | lodash "~4.11.1"
953 |
954 | express@^4.14.0:
955 | version "4.14.0"
956 | resolved "https://registry.yarnpkg.com/express/-/express-4.14.0.tgz#c1ee3f42cdc891fb3dc650a8922d51ec847d0d66"
957 | dependencies:
958 | accepts "~1.3.3"
959 | array-flatten "1.1.1"
960 | content-disposition "0.5.1"
961 | content-type "~1.0.2"
962 | cookie "0.3.1"
963 | cookie-signature "1.0.6"
964 | debug "~2.2.0"
965 | depd "~1.1.0"
966 | encodeurl "~1.0.1"
967 | escape-html "~1.0.3"
968 | etag "~1.7.0"
969 | finalhandler "0.5.0"
970 | fresh "0.3.0"
971 | merge-descriptors "1.0.1"
972 | methods "~1.1.2"
973 | on-finished "~2.3.0"
974 | parseurl "~1.3.1"
975 | path-to-regexp "0.1.7"
976 | proxy-addr "~1.1.2"
977 | qs "6.2.0"
978 | range-parser "~1.2.0"
979 | send "0.14.1"
980 | serve-static "~1.11.1"
981 | type-is "~1.6.13"
982 | utils-merge "1.0.0"
983 | vary "~1.1.0"
984 |
985 | extend@~3.0.0:
986 | version "3.0.0"
987 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
988 |
989 | extglob@^0.3.1:
990 | version "0.3.2"
991 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
992 | dependencies:
993 | is-extglob "^1.0.0"
994 |
995 | extsprintf@1.0.2:
996 | version "1.0.2"
997 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550"
998 |
999 | eyes@0.1.x:
1000 | version "0.1.8"
1001 | resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0"
1002 |
1003 | fast-levenshtein@~2.0.4:
1004 | version "2.0.5"
1005 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.5.tgz#bd33145744519ab1c36c3ee9f31f08e9079b67f2"
1006 |
1007 | figures@^1.3.5:
1008 | version "1.7.0"
1009 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
1010 | dependencies:
1011 | escape-string-regexp "^1.0.5"
1012 | object-assign "^4.1.0"
1013 |
1014 | file-entry-cache@^2.0.0:
1015 | version "2.0.0"
1016 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
1017 | dependencies:
1018 | flat-cache "^1.2.1"
1019 | object-assign "^4.0.1"
1020 |
1021 | filename-regex@^2.0.0:
1022 | version "2.0.0"
1023 | resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
1024 |
1025 | fill-range@^2.1.0:
1026 | version "2.2.3"
1027 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723"
1028 | dependencies:
1029 | is-number "^2.1.0"
1030 | isobject "^2.0.0"
1031 | randomatic "^1.1.3"
1032 | repeat-element "^1.1.2"
1033 | repeat-string "^1.5.2"
1034 |
1035 | finalhandler@0.4.1:
1036 | version "0.4.1"
1037 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.4.1.tgz#85a17c6c59a94717d262d61230d4b0ebe3d4a14d"
1038 | dependencies:
1039 | debug "~2.2.0"
1040 | escape-html "~1.0.3"
1041 | on-finished "~2.3.0"
1042 | unpipe "~1.0.0"
1043 |
1044 | finalhandler@0.5.0:
1045 | version "0.5.0"
1046 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-0.5.0.tgz#e9508abece9b6dba871a6942a1d7911b91911ac7"
1047 | dependencies:
1048 | debug "~2.2.0"
1049 | escape-html "~1.0.3"
1050 | on-finished "~2.3.0"
1051 | statuses "~1.3.0"
1052 | unpipe "~1.0.0"
1053 |
1054 | find-up@^1.0.0:
1055 | version "1.1.2"
1056 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
1057 | dependencies:
1058 | path-exists "^2.0.0"
1059 | pinkie-promise "^2.0.0"
1060 |
1061 | flat-cache@^1.2.1:
1062 | version "1.2.1"
1063 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.1.tgz#6c837d6225a7de5659323740b36d5361f71691ff"
1064 | dependencies:
1065 | circular-json "^0.3.0"
1066 | del "^2.0.2"
1067 | graceful-fs "^4.1.2"
1068 | write "^0.2.1"
1069 |
1070 | for-in@^0.1.5:
1071 | version "0.1.6"
1072 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8"
1073 |
1074 | for-own@^0.1.4:
1075 | version "0.1.4"
1076 | resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072"
1077 | dependencies:
1078 | for-in "^0.1.5"
1079 |
1080 | forever-agent@~0.6.1:
1081 | version "0.6.1"
1082 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
1083 |
1084 | form-data@~2.1.1:
1085 | version "2.1.1"
1086 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.1.tgz#4adf0342e1a79afa1e84c8c320a9ffc82392a1f3"
1087 | dependencies:
1088 | asynckit "^0.4.0"
1089 | combined-stream "^1.0.5"
1090 | mime-types "^2.1.12"
1091 |
1092 | forwarded@~0.1.0:
1093 | version "0.1.0"
1094 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363"
1095 |
1096 | frameguard@3.0.0:
1097 | version "3.0.0"
1098 | resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9"
1099 |
1100 | fresh@0.3.0:
1101 | version "0.3.0"
1102 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f"
1103 |
1104 | from@~0:
1105 | version "0.1.3"
1106 | resolved "https://registry.yarnpkg.com/from/-/from-0.1.3.tgz#ef63ac2062ac32acf7862e0d40b44b896f22f3bc"
1107 |
1108 | fs-readdir-recursive@^1.0.0:
1109 | version "1.0.0"
1110 | resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560"
1111 |
1112 | fs.realpath@^1.0.0:
1113 | version "1.0.0"
1114 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
1115 |
1116 | fsevents@^1.0.0:
1117 | version "1.0.15"
1118 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.15.tgz#fa63f590f3c2ad91275e4972a6cea545fb0aae44"
1119 | dependencies:
1120 | nan "^2.3.0"
1121 | node-pre-gyp "^0.6.29"
1122 |
1123 | fstream-ignore@~1.0.5:
1124 | version "1.0.5"
1125 | resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105"
1126 | dependencies:
1127 | fstream "^1.0.0"
1128 | inherits "2"
1129 | minimatch "^3.0.0"
1130 |
1131 | fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10:
1132 | version "1.0.10"
1133 | resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822"
1134 | dependencies:
1135 | graceful-fs "^4.1.2"
1136 | inherits "~2.0.0"
1137 | mkdirp ">=0.5 0"
1138 | rimraf "2"
1139 |
1140 | function-bind@^1.0.2:
1141 | version "1.1.0"
1142 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
1143 |
1144 | gauge@~2.6.0:
1145 | version "2.6.0"
1146 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.6.0.tgz#d35301ad18e96902b4751dcbbe40f4218b942a46"
1147 | dependencies:
1148 | aproba "^1.0.3"
1149 | console-control-strings "^1.0.0"
1150 | has-color "^0.1.7"
1151 | has-unicode "^2.0.0"
1152 | object-assign "^4.1.0"
1153 | signal-exit "^3.0.0"
1154 | string-width "^1.0.1"
1155 | strip-ansi "^3.0.1"
1156 | wide-align "^1.1.0"
1157 |
1158 | generate-function@^2.0.0:
1159 | version "2.0.0"
1160 | resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
1161 |
1162 | generate-object-property@^1.1.0:
1163 | version "1.2.0"
1164 | resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
1165 | dependencies:
1166 | is-property "^1.0.0"
1167 |
1168 | getpass@^0.1.1:
1169 | version "0.1.6"
1170 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
1171 | dependencies:
1172 | assert-plus "^1.0.0"
1173 |
1174 | glob-base@^0.3.0:
1175 | version "0.3.0"
1176 | resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
1177 | dependencies:
1178 | glob-parent "^2.0.0"
1179 | is-glob "^2.0.0"
1180 |
1181 | glob-parent@^2.0.0:
1182 | version "2.0.0"
1183 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
1184 | dependencies:
1185 | is-glob "^2.0.0"
1186 |
1187 | glob@^5.0.5:
1188 | version "5.0.15"
1189 | resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
1190 | dependencies:
1191 | inflight "^1.0.4"
1192 | inherits "2"
1193 | minimatch "2 || 3"
1194 | once "^1.3.0"
1195 | path-is-absolute "^1.0.0"
1196 |
1197 | glob@^7.0.0, glob@^7.0.3, glob@^7.0.5:
1198 | version "7.1.1"
1199 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
1200 | dependencies:
1201 | fs.realpath "^1.0.0"
1202 | inflight "^1.0.4"
1203 | inherits "2"
1204 | minimatch "^3.0.2"
1205 | once "^1.3.0"
1206 | path-is-absolute "^1.0.0"
1207 |
1208 | globals@^9.0.0, globals@^9.2.0:
1209 | version "9.12.0"
1210 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.12.0.tgz#992ce90828c3a55fa8f16fada177adb64664cf9d"
1211 |
1212 | globby@^5.0.0:
1213 | version "5.0.0"
1214 | resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
1215 | dependencies:
1216 | array-union "^1.0.1"
1217 | arrify "^1.0.0"
1218 | glob "^7.0.3"
1219 | object-assign "^4.0.1"
1220 | pify "^2.0.0"
1221 | pinkie-promise "^2.0.0"
1222 |
1223 | got@^3.2.0:
1224 | version "3.3.1"
1225 | resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca"
1226 | dependencies:
1227 | duplexify "^3.2.0"
1228 | infinity-agent "^2.0.0"
1229 | is-redirect "^1.0.0"
1230 | is-stream "^1.0.0"
1231 | lowercase-keys "^1.0.0"
1232 | nested-error-stacks "^1.0.0"
1233 | object-assign "^3.0.0"
1234 | prepend-http "^1.0.0"
1235 | read-all-stream "^3.0.0"
1236 | timed-out "^2.0.0"
1237 |
1238 | graceful-fs@^4.1.2, graceful-fs@^4.1.4:
1239 | version "4.1.10"
1240 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.10.tgz#f2d720c22092f743228775c75e3612632501f131"
1241 |
1242 | "graceful-readlink@>= 1.0.0":
1243 | version "1.0.1"
1244 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
1245 |
1246 | har-validator@~2.0.6:
1247 | version "2.0.6"
1248 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"
1249 | dependencies:
1250 | chalk "^1.1.1"
1251 | commander "^2.9.0"
1252 | is-my-json-valid "^2.12.4"
1253 | pinkie-promise "^2.0.0"
1254 |
1255 | has-ansi@^2.0.0:
1256 | version "2.0.0"
1257 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
1258 | dependencies:
1259 | ansi-regex "^2.0.0"
1260 |
1261 | has-color@^0.1.7, has-color@~0.1.0:
1262 | version "0.1.7"
1263 | resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
1264 |
1265 | has-unicode@^2.0.0:
1266 | version "2.0.1"
1267 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
1268 |
1269 | has@^1.0.1:
1270 | version "1.0.1"
1271 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
1272 | dependencies:
1273 | function-bind "^1.0.2"
1274 |
1275 | hawk@~3.1.3:
1276 | version "3.1.3"
1277 | resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4"
1278 | dependencies:
1279 | boom "2.x.x"
1280 | cryptiles "2.x.x"
1281 | hoek "2.x.x"
1282 | sntp "1.x.x"
1283 |
1284 | helmet-csp@2.1.0:
1285 | version "2.1.0"
1286 | resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.1.0.tgz#c0fbff8d9e8f3bbff2b83dc7fed3d47143184040"
1287 | dependencies:
1288 | camelize "1.0.0"
1289 | content-security-policy-builder "1.1.0"
1290 | dasherize "2.0.0"
1291 | lodash.reduce "4.6.0"
1292 | platform "1.3.1"
1293 |
1294 | helmet@^3.1.0:
1295 | version "3.1.0"
1296 | resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.1.0.tgz#64449547398e51b063fe1c75e7cb0274a557ea09"
1297 | dependencies:
1298 | connect "3.4.1"
1299 | dns-prefetch-control "0.1.0"
1300 | dont-sniff-mimetype "1.0.0"
1301 | frameguard "3.0.0"
1302 | helmet-csp "2.1.0"
1303 | hide-powered-by "1.0.0"
1304 | hpkp "2.0.0"
1305 | hsts "2.0.0"
1306 | ienoopen "1.0.0"
1307 | nocache "2.0.0"
1308 | referrer-policy "1.0.0"
1309 | x-xss-protection "1.0.0"
1310 |
1311 | hide-powered-by@1.0.0:
1312 | version "1.0.0"
1313 | resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b"
1314 |
1315 | hoek@2.x.x:
1316 | version "2.16.3"
1317 | resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
1318 |
1319 | home-or-tmp@^2.0.0:
1320 | version "2.0.0"
1321 | resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
1322 | dependencies:
1323 | os-homedir "^1.0.0"
1324 | os-tmpdir "^1.0.1"
1325 |
1326 | hpkp@2.0.0:
1327 | version "2.0.0"
1328 | resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672"
1329 |
1330 | hsts@2.0.0:
1331 | version "2.0.0"
1332 | resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.0.0.tgz#a52234c6070decf214b2b6b70bb144d07e4776c7"
1333 | dependencies:
1334 | core-util-is "1.0.2"
1335 |
1336 | http-errors@~1.5.0:
1337 | version "1.5.0"
1338 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.0.tgz#b1cb3d8260fd8e2386cad3189045943372d48211"
1339 | dependencies:
1340 | inherits "2.0.1"
1341 | setprototypeof "1.0.1"
1342 | statuses ">= 1.3.0 < 2"
1343 |
1344 | http-signature@~1.1.0:
1345 | version "1.1.1"
1346 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
1347 | dependencies:
1348 | assert-plus "^0.2.0"
1349 | jsprim "^1.2.2"
1350 | sshpk "^1.7.0"
1351 |
1352 | iconv-lite@0.4.13:
1353 | version "0.4.13"
1354 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
1355 |
1356 | ienoopen@1.0.0:
1357 | version "1.0.0"
1358 | resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b"
1359 |
1360 | ignore-by-default@^1.0.0:
1361 | version "1.0.1"
1362 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
1363 |
1364 | ignore@^3.1.5:
1365 | version "3.2.0"
1366 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435"
1367 |
1368 | imurmurhash@^0.1.4:
1369 | version "0.1.4"
1370 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
1371 |
1372 | infinity-agent@^2.0.0:
1373 | version "2.0.3"
1374 | resolved "https://registry.yarnpkg.com/infinity-agent/-/infinity-agent-2.0.3.tgz#45e0e2ff7a9eb030b27d62b74b3744b7a7ac4216"
1375 |
1376 | inflection@^1.8.0:
1377 | version "1.10.0"
1378 | resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f"
1379 |
1380 | inflight@^1.0.4:
1381 | version "1.0.6"
1382 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
1383 | dependencies:
1384 | once "^1.3.0"
1385 | wrappy "1"
1386 |
1387 | inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@2:
1388 | version "2.0.3"
1389 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
1390 |
1391 | inherits@2.0.1:
1392 | version "2.0.1"
1393 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
1394 |
1395 | ini@~1.3.0:
1396 | version "1.3.4"
1397 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
1398 |
1399 | inquirer@^0.12.0:
1400 | version "0.12.0"
1401 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
1402 | dependencies:
1403 | ansi-escapes "^1.1.0"
1404 | ansi-regex "^2.0.0"
1405 | chalk "^1.0.0"
1406 | cli-cursor "^1.0.1"
1407 | cli-width "^2.0.0"
1408 | figures "^1.3.5"
1409 | lodash "^4.3.0"
1410 | readline2 "^1.0.1"
1411 | run-async "^0.1.0"
1412 | rx-lite "^3.1.2"
1413 | string-width "^1.0.1"
1414 | strip-ansi "^3.0.0"
1415 | through "^2.3.6"
1416 |
1417 | interpret@^1.0.0:
1418 | version "1.0.1"
1419 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c"
1420 |
1421 | invariant@^2.2.0:
1422 | version "2.2.1"
1423 | resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.1.tgz#b097010547668c7e337028ebe816ebe36c8a8d54"
1424 | dependencies:
1425 | loose-envify "^1.0.0"
1426 |
1427 | ipaddr.js@1.1.1:
1428 | version "1.1.1"
1429 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.1.1.tgz#c791d95f52b29c1247d5df80ada39b8a73647230"
1430 |
1431 | is-binary-path@^1.0.0:
1432 | version "1.0.1"
1433 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
1434 | dependencies:
1435 | binary-extensions "^1.0.0"
1436 |
1437 | is-buffer@^1.0.2:
1438 | version "1.1.4"
1439 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b"
1440 |
1441 | is-dotfile@^1.0.0:
1442 | version "1.0.2"
1443 | resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
1444 |
1445 | is-equal-shallow@^0.1.3:
1446 | version "0.1.3"
1447 | resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
1448 | dependencies:
1449 | is-primitive "^2.0.0"
1450 |
1451 | is-extendable@^0.1.1:
1452 | version "0.1.1"
1453 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
1454 |
1455 | is-extglob@^1.0.0:
1456 | version "1.0.0"
1457 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
1458 |
1459 | is-finite@^1.0.0:
1460 | version "1.0.2"
1461 | resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
1462 | dependencies:
1463 | number-is-nan "^1.0.0"
1464 |
1465 | is-fullwidth-code-point@^1.0.0:
1466 | version "1.0.0"
1467 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
1468 | dependencies:
1469 | number-is-nan "^1.0.0"
1470 |
1471 | is-fullwidth-code-point@^2.0.0:
1472 | version "2.0.0"
1473 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
1474 |
1475 | is-glob@^2.0.0, is-glob@^2.0.1:
1476 | version "2.0.1"
1477 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
1478 | dependencies:
1479 | is-extglob "^1.0.0"
1480 |
1481 | is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4:
1482 | version "2.15.0"
1483 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b"
1484 | dependencies:
1485 | generate-function "^2.0.0"
1486 | generate-object-property "^1.1.0"
1487 | jsonpointer "^4.0.0"
1488 | xtend "^4.0.0"
1489 |
1490 | is-npm@^1.0.0:
1491 | version "1.0.0"
1492 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
1493 |
1494 | is-number@^2.0.2, is-number@^2.1.0:
1495 | version "2.1.0"
1496 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
1497 | dependencies:
1498 | kind-of "^3.0.2"
1499 |
1500 | is-path-cwd@^1.0.0:
1501 | version "1.0.0"
1502 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
1503 |
1504 | is-path-in-cwd@^1.0.0:
1505 | version "1.0.0"
1506 | resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc"
1507 | dependencies:
1508 | is-path-inside "^1.0.0"
1509 |
1510 | is-path-inside@^1.0.0:
1511 | version "1.0.0"
1512 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
1513 | dependencies:
1514 | path-is-inside "^1.0.1"
1515 |
1516 | is-posix-bracket@^0.1.0:
1517 | version "0.1.1"
1518 | resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
1519 |
1520 | is-primitive@^2.0.0:
1521 | version "2.0.0"
1522 | resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
1523 |
1524 | is-property@^1.0.0:
1525 | version "1.0.2"
1526 | resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
1527 |
1528 | is-redirect@^1.0.0:
1529 | version "1.0.0"
1530 | resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
1531 |
1532 | is-resolvable@^1.0.0:
1533 | version "1.0.0"
1534 | resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
1535 | dependencies:
1536 | tryit "^1.0.1"
1537 |
1538 | is-stream@^1.0.0:
1539 | version "1.1.0"
1540 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
1541 |
1542 | is-typedarray@~1.0.0:
1543 | version "1.0.0"
1544 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
1545 |
1546 | isarray@^1.0.0, isarray@~1.0.0, isarray@1.0.0:
1547 | version "1.0.0"
1548 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
1549 |
1550 | isobject@^2.0.0:
1551 | version "2.1.0"
1552 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
1553 | dependencies:
1554 | isarray "1.0.0"
1555 |
1556 | isstream@~0.1.2, isstream@0.1.x:
1557 | version "0.1.2"
1558 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
1559 |
1560 | jodid25519@^1.0.0:
1561 | version "1.0.2"
1562 | resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
1563 | dependencies:
1564 | jsbn "~0.1.0"
1565 |
1566 | js-tokens@^2.0.0:
1567 | version "2.0.0"
1568 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5"
1569 |
1570 | js-yaml@^3.5.1:
1571 | version "3.6.1"
1572 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30"
1573 | dependencies:
1574 | argparse "^1.0.7"
1575 | esprima "^2.6.0"
1576 |
1577 | jsbn@~0.1.0:
1578 | version "0.1.0"
1579 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd"
1580 |
1581 | jsesc@^1.3.0:
1582 | version "1.3.0"
1583 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
1584 |
1585 | json-inflector:
1586 | version "1.1.0"
1587 | resolved "https://registry.yarnpkg.com/json-inflector/-/json-inflector-1.1.0.tgz#bcacb816423ffe49f6b9e37db4e99ede29d9f1d4"
1588 | dependencies:
1589 | inflection "^1.8.0"
1590 |
1591 | json-schema@0.2.3:
1592 | version "0.2.3"
1593 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
1594 |
1595 | json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
1596 | version "1.0.1"
1597 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
1598 | dependencies:
1599 | jsonify "~0.0.0"
1600 |
1601 | json-stringify-safe@~5.0.1:
1602 | version "5.0.1"
1603 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
1604 |
1605 | json5@^0.5.0:
1606 | version "0.5.0"
1607 | resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.0.tgz#9b20715b026cbe3778fd769edccd822d8332a5b2"
1608 |
1609 | jsonify@~0.0.0:
1610 | version "0.0.0"
1611 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
1612 |
1613 | jsonpointer@^4.0.0:
1614 | version "4.0.0"
1615 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.0.tgz#6661e161d2fc445f19f98430231343722e1fcbd5"
1616 |
1617 | jsprim@^1.2.2:
1618 | version "1.3.1"
1619 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252"
1620 | dependencies:
1621 | extsprintf "1.0.2"
1622 | json-schema "0.2.3"
1623 | verror "1.3.6"
1624 |
1625 | kind-of@^3.0.2:
1626 | version "3.0.4"
1627 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74"
1628 | dependencies:
1629 | is-buffer "^1.0.2"
1630 |
1631 | latest-version@^1.0.0:
1632 | version "1.0.1"
1633 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-1.0.1.tgz#72cfc46e3e8d1be651e1ebb54ea9f6ea96f374bb"
1634 | dependencies:
1635 | package-json "^1.0.0"
1636 |
1637 | levn@^0.3.0, levn@~0.3.0:
1638 | version "0.3.0"
1639 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
1640 | dependencies:
1641 | prelude-ls "~1.1.2"
1642 | type-check "~0.3.2"
1643 |
1644 | lodash._baseassign@^3.0.0:
1645 | version "3.2.0"
1646 | resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e"
1647 | dependencies:
1648 | lodash._basecopy "^3.0.0"
1649 | lodash.keys "^3.0.0"
1650 |
1651 | lodash._basecopy@^3.0.0:
1652 | version "3.0.1"
1653 | resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"
1654 |
1655 | lodash._bindcallback@^3.0.0:
1656 | version "3.0.1"
1657 | resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
1658 |
1659 | lodash._createassigner@^3.0.0:
1660 | version "3.1.1"
1661 | resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11"
1662 | dependencies:
1663 | lodash._bindcallback "^3.0.0"
1664 | lodash._isiterateecall "^3.0.0"
1665 | lodash.restparam "^3.0.0"
1666 |
1667 | lodash._getnative@^3.0.0:
1668 | version "3.9.1"
1669 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
1670 |
1671 | lodash._isiterateecall@^3.0.0:
1672 | version "3.0.9"
1673 | resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c"
1674 |
1675 | lodash.assign@^3.0.0:
1676 | version "3.2.0"
1677 | resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa"
1678 | dependencies:
1679 | lodash._baseassign "^3.0.0"
1680 | lodash._createassigner "^3.0.0"
1681 | lodash.keys "^3.0.0"
1682 |
1683 | lodash.cond@^4.3.0:
1684 | version "4.5.2"
1685 | resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5"
1686 |
1687 | lodash.defaults@^3.1.2:
1688 | version "3.1.2"
1689 | resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-3.1.2.tgz#c7308b18dbf8bc9372d701a73493c61192bd2e2c"
1690 | dependencies:
1691 | lodash.assign "^3.0.0"
1692 | lodash.restparam "^3.0.0"
1693 |
1694 | lodash.isarguments@^3.0.0:
1695 | version "3.1.0"
1696 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
1697 |
1698 | lodash.isarray@^3.0.0:
1699 | version "3.0.4"
1700 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
1701 |
1702 | lodash.keys@^3.0.0:
1703 | version "3.1.2"
1704 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
1705 | dependencies:
1706 | lodash._getnative "^3.0.0"
1707 | lodash.isarguments "^3.0.0"
1708 | lodash.isarray "^3.0.0"
1709 |
1710 | lodash.pickby@^4.6.0:
1711 | version "4.6.0"
1712 | resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff"
1713 |
1714 | lodash.reduce@4.6.0:
1715 | version "4.6.0"
1716 | resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b"
1717 |
1718 | lodash.restparam@^3.0.0:
1719 | version "3.6.1"
1720 | resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"
1721 |
1722 | lodash@^4.0.0, lodash@^4.2.0, lodash@^4.3.0:
1723 | version "4.16.6"
1724 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777"
1725 |
1726 | lodash@~4.11.1:
1727 | version "4.11.2"
1728 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.11.2.tgz#d6b4338b110a58e21dae5cebcfdbbfd2bc4cdb3b"
1729 |
1730 | loose-envify@^1.0.0:
1731 | version "1.3.0"
1732 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.0.tgz#6b26248c42f6d4fa4b0d8542f78edfcde35642a8"
1733 | dependencies:
1734 | js-tokens "^2.0.0"
1735 |
1736 | lowercase-keys@^1.0.0:
1737 | version "1.0.0"
1738 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306"
1739 |
1740 | map-stream@~0.1.0:
1741 | version "0.1.0"
1742 | resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
1743 |
1744 | media-typer@0.3.0:
1745 | version "0.3.0"
1746 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
1747 |
1748 | merge-descriptors@1.0.1:
1749 | version "1.0.1"
1750 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
1751 |
1752 | methods@~1.1.2:
1753 | version "1.1.2"
1754 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
1755 |
1756 | micromatch@^2.1.5:
1757 | version "2.3.11"
1758 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
1759 | dependencies:
1760 | arr-diff "^2.0.0"
1761 | array-unique "^0.2.1"
1762 | braces "^1.8.2"
1763 | expand-brackets "^0.1.4"
1764 | extglob "^0.3.1"
1765 | filename-regex "^2.0.0"
1766 | is-extglob "^1.0.0"
1767 | is-glob "^2.0.1"
1768 | kind-of "^3.0.2"
1769 | normalize-path "^2.0.1"
1770 | object.omit "^2.0.0"
1771 | parse-glob "^3.0.4"
1772 | regex-cache "^0.4.2"
1773 |
1774 | mime-db@~1.24.0:
1775 | version "1.24.0"
1776 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.24.0.tgz#e2d13f939f0016c6e4e9ad25a8652f126c467f0c"
1777 |
1778 | mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.7:
1779 | version "2.1.12"
1780 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.12.tgz#152ba256777020dd4663f54c2e7bc26381e71729"
1781 | dependencies:
1782 | mime-db "~1.24.0"
1783 |
1784 | mime@1.3.4:
1785 | version "1.3.4"
1786 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
1787 |
1788 | minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, "minimatch@2 || 3":
1789 | version "3.0.3"
1790 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
1791 | dependencies:
1792 | brace-expansion "^1.0.0"
1793 |
1794 | minimist@^1.2.0:
1795 | version "1.2.0"
1796 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
1797 |
1798 | minimist@0.0.8:
1799 | version "0.0.8"
1800 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
1801 |
1802 | mkdirp@^0.5.0, mkdirp@^0.5.1, "mkdirp@>=0.5 0", mkdirp@~0.5.1:
1803 | version "0.5.1"
1804 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
1805 | dependencies:
1806 | minimist "0.0.8"
1807 |
1808 | ms@0.7.1:
1809 | version "0.7.1"
1810 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
1811 |
1812 | mute-stream@0.0.5:
1813 | version "0.0.5"
1814 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
1815 |
1816 | nan@^2.3.0:
1817 | version "2.4.0"
1818 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232"
1819 |
1820 | natural-compare@^1.4.0:
1821 | version "1.4.0"
1822 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
1823 |
1824 | negotiator@0.6.1:
1825 | version "0.6.1"
1826 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
1827 |
1828 | nested-error-stacks@^1.0.0:
1829 | version "1.0.2"
1830 | resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz#19f619591519f096769a5ba9a86e6eeec823c3cf"
1831 | dependencies:
1832 | inherits "~2.0.1"
1833 |
1834 | nocache@2.0.0:
1835 | version "2.0.0"
1836 | resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980"
1837 |
1838 | node-pre-gyp@^0.6.29:
1839 | version "0.6.31"
1840 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.31.tgz#d8a00ddaa301a940615dbcc8caad4024d58f6017"
1841 | dependencies:
1842 | mkdirp "~0.5.1"
1843 | nopt "~3.0.6"
1844 | npmlog "^4.0.0"
1845 | rc "~1.1.6"
1846 | request "^2.75.0"
1847 | rimraf "~2.5.4"
1848 | semver "~5.3.0"
1849 | tar "~2.2.1"
1850 | tar-pack "~3.3.0"
1851 |
1852 | node-uuid@~1.4.7:
1853 | version "1.4.7"
1854 | resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f"
1855 |
1856 | nodemon@^1.11.0:
1857 | version "1.11.0"
1858 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.11.0.tgz#226c562bd2a7b13d3d7518b49ad4828a3623d06c"
1859 | dependencies:
1860 | chokidar "^1.4.3"
1861 | debug "^2.2.0"
1862 | es6-promise "^3.0.2"
1863 | ignore-by-default "^1.0.0"
1864 | lodash.defaults "^3.1.2"
1865 | minimatch "^3.0.0"
1866 | ps-tree "^1.0.1"
1867 | touch "1.0.0"
1868 | undefsafe "0.0.3"
1869 | update-notifier "0.5.0"
1870 |
1871 | nopt@~1.0.10:
1872 | version "1.0.10"
1873 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
1874 | dependencies:
1875 | abbrev "1"
1876 |
1877 | nopt@~3.0.6:
1878 | version "3.0.6"
1879 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
1880 | dependencies:
1881 | abbrev "1"
1882 |
1883 | normalize-path@^2.0.1:
1884 | version "2.0.1"
1885 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a"
1886 |
1887 | npmlog@^4.0.0:
1888 | version "4.0.0"
1889 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.0.tgz#e094503961c70c1774eb76692080e8d578a9f88f"
1890 | dependencies:
1891 | are-we-there-yet "~1.1.2"
1892 | console-control-strings "~1.1.0"
1893 | gauge "~2.6.0"
1894 | set-blocking "~2.0.0"
1895 |
1896 | number-is-nan@^1.0.0:
1897 | version "1.0.1"
1898 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
1899 |
1900 | oauth-sign@~0.8.1:
1901 | version "0.8.2"
1902 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
1903 |
1904 | object-assign@^3.0.0:
1905 | version "3.0.0"
1906 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
1907 |
1908 | object-assign@^4.0.1, object-assign@^4.1.0:
1909 | version "4.1.0"
1910 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0"
1911 |
1912 | object.omit@^2.0.0:
1913 | version "2.0.1"
1914 | resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
1915 | dependencies:
1916 | for-own "^0.1.4"
1917 | is-extendable "^0.1.1"
1918 |
1919 | on-finished@~2.3.0:
1920 | version "2.3.0"
1921 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
1922 | dependencies:
1923 | ee-first "1.1.1"
1924 |
1925 | once@^1.3.0:
1926 | version "1.4.0"
1927 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
1928 | dependencies:
1929 | wrappy "1"
1930 |
1931 | once@~1.3.0, once@~1.3.3:
1932 | version "1.3.3"
1933 | resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20"
1934 | dependencies:
1935 | wrappy "1"
1936 |
1937 | onetime@^1.0.0:
1938 | version "1.1.0"
1939 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
1940 |
1941 | optionator@^0.8.2:
1942 | version "0.8.2"
1943 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
1944 | dependencies:
1945 | deep-is "~0.1.3"
1946 | fast-levenshtein "~2.0.4"
1947 | levn "~0.3.0"
1948 | prelude-ls "~1.1.2"
1949 | type-check "~0.3.2"
1950 | wordwrap "~1.0.0"
1951 |
1952 | os-homedir@^1.0.0:
1953 | version "1.0.2"
1954 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
1955 |
1956 | os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
1957 | version "1.0.2"
1958 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
1959 |
1960 | osenv@^0.1.0:
1961 | version "0.1.3"
1962 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.3.tgz#83cf05c6d6458fc4d5ac6362ea325d92f2754217"
1963 | dependencies:
1964 | os-homedir "^1.0.0"
1965 | os-tmpdir "^1.0.0"
1966 |
1967 | output-file-sync@^1.1.0:
1968 | version "1.1.2"
1969 | resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76"
1970 | dependencies:
1971 | graceful-fs "^4.1.4"
1972 | mkdirp "^0.5.1"
1973 | object-assign "^4.1.0"
1974 |
1975 | package-json@^1.0.0:
1976 | version "1.2.0"
1977 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-1.2.0.tgz#c8ecac094227cdf76a316874ed05e27cc939a0e0"
1978 | dependencies:
1979 | got "^3.2.0"
1980 | registry-url "^3.0.0"
1981 |
1982 | parse-glob@^3.0.4:
1983 | version "3.0.4"
1984 | resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
1985 | dependencies:
1986 | glob-base "^0.3.0"
1987 | is-dotfile "^1.0.0"
1988 | is-extglob "^1.0.0"
1989 | is-glob "^2.0.0"
1990 |
1991 | parseurl@~1.3.1:
1992 | version "1.3.1"
1993 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56"
1994 |
1995 | path-exists@^2.0.0:
1996 | version "2.1.0"
1997 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
1998 | dependencies:
1999 | pinkie-promise "^2.0.0"
2000 |
2001 | path-is-absolute@^1.0.0:
2002 | version "1.0.1"
2003 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
2004 |
2005 | path-is-inside@^1.0.1:
2006 | version "1.0.2"
2007 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
2008 |
2009 | path-to-regexp@0.1.7:
2010 | version "0.1.7"
2011 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
2012 |
2013 | pause-stream@0.0.11:
2014 | version "0.0.11"
2015 | resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
2016 | dependencies:
2017 | through "~2.3"
2018 |
2019 | pify@^2.0.0:
2020 | version "2.3.0"
2021 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
2022 |
2023 | pinkie-promise@^2.0.0:
2024 | version "2.0.1"
2025 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
2026 | dependencies:
2027 | pinkie "^2.0.0"
2028 |
2029 | pinkie@^2.0.0:
2030 | version "2.0.4"
2031 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
2032 |
2033 | pkg-dir@^1.0.0:
2034 | version "1.0.0"
2035 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
2036 | dependencies:
2037 | find-up "^1.0.0"
2038 |
2039 | pkg-up@^1.0.0:
2040 | version "1.0.0"
2041 | resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26"
2042 | dependencies:
2043 | find-up "^1.0.0"
2044 |
2045 | platform@1.3.1:
2046 | version "1.3.1"
2047 | resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.1.tgz#492210892335bd3131c0a08dda2d93ec3543e423"
2048 |
2049 | pluralize@^1.2.1:
2050 | version "1.2.1"
2051 | resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
2052 |
2053 | prelude-ls@~1.1.2:
2054 | version "1.1.2"
2055 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
2056 |
2057 | prepend-http@^1.0.0:
2058 | version "1.0.4"
2059 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
2060 |
2061 | preserve@^0.2.0:
2062 | version "0.2.0"
2063 | resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
2064 |
2065 | private@^0.1.6:
2066 | version "0.1.6"
2067 | resolved "https://registry.yarnpkg.com/private/-/private-0.1.6.tgz#55c6a976d0f9bafb9924851350fe47b9b5fbb7c1"
2068 |
2069 | process-nextick-args@~1.0.6:
2070 | version "1.0.7"
2071 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
2072 |
2073 | progress@^1.1.8:
2074 | version "1.1.8"
2075 | resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
2076 |
2077 | proxy-addr@~1.1.2:
2078 | version "1.1.2"
2079 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.2.tgz#b4cc5f22610d9535824c123aef9d3cf73c40ba37"
2080 | dependencies:
2081 | forwarded "~0.1.0"
2082 | ipaddr.js "1.1.1"
2083 |
2084 | ps-tree@^1.0.1:
2085 | version "1.1.0"
2086 | resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014"
2087 | dependencies:
2088 | event-stream "~3.3.0"
2089 |
2090 | punycode@^1.4.1:
2091 | version "1.4.1"
2092 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
2093 |
2094 | qs@~6.3.0:
2095 | version "6.3.0"
2096 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442"
2097 |
2098 | qs@6.2.0:
2099 | version "6.2.0"
2100 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.0.tgz#3b7848c03c2dece69a9522b0fae8c4126d745f3b"
2101 |
2102 | randomatic@^1.1.3:
2103 | version "1.1.5"
2104 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.5.tgz#5e9ef5f2d573c67bd2b8124ae90b5156e457840b"
2105 | dependencies:
2106 | is-number "^2.0.2"
2107 | kind-of "^3.0.2"
2108 |
2109 | range-parser@~1.2.0:
2110 | version "1.2.0"
2111 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
2112 |
2113 | raw-body@~2.1.7:
2114 | version "2.1.7"
2115 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774"
2116 | dependencies:
2117 | bytes "2.4.0"
2118 | iconv-lite "0.4.13"
2119 | unpipe "1.0.0"
2120 |
2121 | rc@^1.0.1, rc@~1.1.6:
2122 | version "1.1.6"
2123 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9"
2124 | dependencies:
2125 | deep-extend "~0.4.0"
2126 | ini "~1.3.0"
2127 | minimist "^1.2.0"
2128 | strip-json-comments "~1.0.4"
2129 |
2130 | read-all-stream@^3.0.0:
2131 | version "3.1.0"
2132 | resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
2133 | dependencies:
2134 | pinkie-promise "^2.0.0"
2135 | readable-stream "^2.0.0"
2136 |
2137 | readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@~2.1.4:
2138 | version "2.1.5"
2139 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0"
2140 | dependencies:
2141 | buffer-shims "^1.0.0"
2142 | core-util-is "~1.0.0"
2143 | inherits "~2.0.1"
2144 | isarray "~1.0.0"
2145 | process-nextick-args "~1.0.6"
2146 | string_decoder "~0.10.x"
2147 | util-deprecate "~1.0.1"
2148 |
2149 | readable-stream@~2.0.0:
2150 | version "2.0.6"
2151 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e"
2152 | dependencies:
2153 | core-util-is "~1.0.0"
2154 | inherits "~2.0.1"
2155 | isarray "~1.0.0"
2156 | process-nextick-args "~1.0.6"
2157 | string_decoder "~0.10.x"
2158 | util-deprecate "~1.0.1"
2159 |
2160 | readdirp@^2.0.0:
2161 | version "2.1.0"
2162 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
2163 | dependencies:
2164 | graceful-fs "^4.1.2"
2165 | minimatch "^3.0.2"
2166 | readable-stream "^2.0.2"
2167 | set-immediate-shim "^1.0.1"
2168 |
2169 | readline2@^1.0.1:
2170 | version "1.0.1"
2171 | resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
2172 | dependencies:
2173 | code-point-at "^1.0.0"
2174 | is-fullwidth-code-point "^1.0.0"
2175 | mute-stream "0.0.5"
2176 |
2177 | rechoir@^0.6.2:
2178 | version "0.6.2"
2179 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
2180 | dependencies:
2181 | resolve "^1.1.6"
2182 |
2183 | referrer-policy@1.0.0:
2184 | version "1.0.0"
2185 | resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.0.0.tgz#f60eedc92f942b01a6118121ec932d66e8fd7e14"
2186 |
2187 | regenerator-runtime@^0.9.5:
2188 | version "0.9.6"
2189 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029"
2190 |
2191 | regex-cache@^0.4.2:
2192 | version "0.4.3"
2193 | resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
2194 | dependencies:
2195 | is-equal-shallow "^0.1.3"
2196 | is-primitive "^2.0.0"
2197 |
2198 | registry-url@^3.0.0:
2199 | version "3.1.0"
2200 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
2201 | dependencies:
2202 | rc "^1.0.1"
2203 |
2204 | repeat-element@^1.1.2:
2205 | version "1.1.2"
2206 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a"
2207 |
2208 | repeat-string@^1.5.2:
2209 | version "1.6.1"
2210 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
2211 |
2212 | repeating@^1.1.2:
2213 | version "1.1.3"
2214 | resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac"
2215 | dependencies:
2216 | is-finite "^1.0.0"
2217 |
2218 | repeating@^2.0.0:
2219 | version "2.0.1"
2220 | resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
2221 | dependencies:
2222 | is-finite "^1.0.0"
2223 |
2224 | request@^2.75.0:
2225 | version "2.78.0"
2226 | resolved "https://registry.yarnpkg.com/request/-/request-2.78.0.tgz#e1c8dec346e1c81923b24acdb337f11decabe9cc"
2227 | dependencies:
2228 | aws-sign2 "~0.6.0"
2229 | aws4 "^1.2.1"
2230 | caseless "~0.11.0"
2231 | combined-stream "~1.0.5"
2232 | extend "~3.0.0"
2233 | forever-agent "~0.6.1"
2234 | form-data "~2.1.1"
2235 | har-validator "~2.0.6"
2236 | hawk "~3.1.3"
2237 | http-signature "~1.1.0"
2238 | is-typedarray "~1.0.0"
2239 | isstream "~0.1.2"
2240 | json-stringify-safe "~5.0.1"
2241 | mime-types "~2.1.7"
2242 | node-uuid "~1.4.7"
2243 | oauth-sign "~0.8.1"
2244 | qs "~6.3.0"
2245 | stringstream "~0.0.4"
2246 | tough-cookie "~2.3.0"
2247 | tunnel-agent "~0.4.1"
2248 |
2249 | require-uncached@^1.0.2:
2250 | version "1.0.3"
2251 | resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
2252 | dependencies:
2253 | caller-path "^0.1.0"
2254 | resolve-from "^1.0.0"
2255 |
2256 | resolve-from@^1.0.0:
2257 | version "1.0.1"
2258 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
2259 |
2260 | resolve@^1.1.6:
2261 | version "1.1.7"
2262 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
2263 |
2264 | restore-cursor@^1.0.1:
2265 | version "1.0.1"
2266 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
2267 | dependencies:
2268 | exit-hook "^1.0.0"
2269 | onetime "^1.0.0"
2270 |
2271 | rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4, rimraf@2:
2272 | version "2.5.4"
2273 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
2274 | dependencies:
2275 | glob "^7.0.5"
2276 |
2277 | run-async@^0.1.0:
2278 | version "0.1.0"
2279 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
2280 | dependencies:
2281 | once "^1.3.0"
2282 |
2283 | rx-lite@^3.1.2:
2284 | version "3.1.2"
2285 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
2286 |
2287 | semver-diff@^2.0.0:
2288 | version "2.1.0"
2289 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
2290 | dependencies:
2291 | semver "^5.0.3"
2292 |
2293 | semver@^5.0.3, semver@~5.3.0:
2294 | version "5.3.0"
2295 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
2296 |
2297 | send@0.14.1:
2298 | version "0.14.1"
2299 | resolved "https://registry.yarnpkg.com/send/-/send-0.14.1.tgz#a954984325392f51532a7760760e459598c89f7a"
2300 | dependencies:
2301 | debug "~2.2.0"
2302 | depd "~1.1.0"
2303 | destroy "~1.0.4"
2304 | encodeurl "~1.0.1"
2305 | escape-html "~1.0.3"
2306 | etag "~1.7.0"
2307 | fresh "0.3.0"
2308 | http-errors "~1.5.0"
2309 | mime "1.3.4"
2310 | ms "0.7.1"
2311 | on-finished "~2.3.0"
2312 | range-parser "~1.2.0"
2313 | statuses "~1.3.0"
2314 |
2315 | serve-static@~1.11.1:
2316 | version "1.11.1"
2317 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.11.1.tgz#d6cce7693505f733c759de57befc1af76c0f0805"
2318 | dependencies:
2319 | encodeurl "~1.0.1"
2320 | escape-html "~1.0.3"
2321 | parseurl "~1.3.1"
2322 | send "0.14.1"
2323 |
2324 | set-blocking@~2.0.0:
2325 | version "2.0.0"
2326 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
2327 |
2328 | set-immediate-shim@^1.0.1:
2329 | version "1.0.1"
2330 | resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
2331 |
2332 | setprototypeof@1.0.1:
2333 | version "1.0.1"
2334 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.1.tgz#52009b27888c4dc48f591949c0a8275834c1ca7e"
2335 |
2336 | shelljs@^0.7.5:
2337 | version "0.7.5"
2338 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.5.tgz#2eef7a50a21e1ccf37da00df767ec69e30ad0675"
2339 | dependencies:
2340 | glob "^7.0.0"
2341 | interpret "^1.0.0"
2342 | rechoir "^0.6.2"
2343 |
2344 | signal-exit@^3.0.0:
2345 | version "3.0.1"
2346 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.1.tgz#5a4c884992b63a7acd9badb7894c3ee9cfccad81"
2347 |
2348 | slash@^1.0.0:
2349 | version "1.0.0"
2350 | resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
2351 |
2352 | slice-ansi@0.0.4:
2353 | version "0.0.4"
2354 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
2355 |
2356 | slide@^1.1.5:
2357 | version "1.1.6"
2358 | resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
2359 |
2360 | sntp@1.x.x:
2361 | version "1.0.9"
2362 | resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
2363 | dependencies:
2364 | hoek "2.x.x"
2365 |
2366 | source-map-support@^0.4.2:
2367 | version "0.4.6"
2368 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.6.tgz#32552aa64b458392a85eab3b0b5ee61527167aeb"
2369 | dependencies:
2370 | source-map "^0.5.3"
2371 |
2372 | source-map@^0.5.0, source-map@^0.5.3:
2373 | version "0.5.6"
2374 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
2375 |
2376 | split@0.3:
2377 | version "0.3.3"
2378 | resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f"
2379 | dependencies:
2380 | through "2"
2381 |
2382 | sprintf-js@~1.0.2:
2383 | version "1.0.3"
2384 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
2385 |
2386 | sshpk@^1.7.0:
2387 | version "1.10.1"
2388 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.1.tgz#30e1a5d329244974a1af61511339d595af6638b0"
2389 | dependencies:
2390 | asn1 "~0.2.3"
2391 | assert-plus "^1.0.0"
2392 | dashdash "^1.12.0"
2393 | getpass "^0.1.1"
2394 | optionalDependencies:
2395 | bcrypt-pbkdf "^1.0.0"
2396 | ecc-jsbn "~0.1.1"
2397 | jodid25519 "^1.0.0"
2398 | jsbn "~0.1.0"
2399 | tweetnacl "~0.14.0"
2400 |
2401 | stack-trace@0.0.x:
2402 | version "0.0.9"
2403 | resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695"
2404 |
2405 | "statuses@>= 1.3.0 < 2", statuses@~1.3.0:
2406 | version "1.3.0"
2407 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.0.tgz#8e55758cb20e7682c1f4fce8dcab30bf01d1e07a"
2408 |
2409 | stream-combiner@~0.0.4:
2410 | version "0.0.4"
2411 | resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14"
2412 | dependencies:
2413 | duplexer "~0.1.1"
2414 |
2415 | stream-shift@^1.0.0:
2416 | version "1.0.0"
2417 | resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
2418 |
2419 | string_decoder@~0.10.x:
2420 | version "0.10.31"
2421 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
2422 |
2423 | string-length@^1.0.0:
2424 | version "1.0.1"
2425 | resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
2426 | dependencies:
2427 | strip-ansi "^3.0.0"
2428 |
2429 | string-width@^1.0.1:
2430 | version "1.0.2"
2431 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
2432 | dependencies:
2433 | code-point-at "^1.0.0"
2434 | is-fullwidth-code-point "^1.0.0"
2435 | strip-ansi "^3.0.0"
2436 |
2437 | string-width@^2.0.0:
2438 | version "2.0.0"
2439 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e"
2440 | dependencies:
2441 | is-fullwidth-code-point "^2.0.0"
2442 | strip-ansi "^3.0.0"
2443 |
2444 | stringstream@~0.0.4:
2445 | version "0.0.5"
2446 | resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
2447 |
2448 | strip-ansi@^3.0.0, strip-ansi@^3.0.1:
2449 | version "3.0.1"
2450 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
2451 | dependencies:
2452 | ansi-regex "^2.0.0"
2453 |
2454 | strip-ansi@~0.1.0:
2455 | version "0.1.1"
2456 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
2457 |
2458 | strip-bom@^3.0.0:
2459 | version "3.0.0"
2460 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
2461 |
2462 | strip-json-comments@~1.0.1, strip-json-comments@~1.0.4:
2463 | version "1.0.4"
2464 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
2465 |
2466 | supports-color@^2.0.0:
2467 | version "2.0.0"
2468 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
2469 |
2470 | table@^3.7.8:
2471 | version "3.8.3"
2472 | resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
2473 | dependencies:
2474 | ajv "^4.7.0"
2475 | ajv-keywords "^1.0.0"
2476 | chalk "^1.1.1"
2477 | lodash "^4.0.0"
2478 | slice-ansi "0.0.4"
2479 | string-width "^2.0.0"
2480 |
2481 | tar-pack@~3.3.0:
2482 | version "3.3.0"
2483 | resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae"
2484 | dependencies:
2485 | debug "~2.2.0"
2486 | fstream "~1.0.10"
2487 | fstream-ignore "~1.0.5"
2488 | once "~1.3.3"
2489 | readable-stream "~2.1.4"
2490 | rimraf "~2.5.1"
2491 | tar "~2.2.1"
2492 | uid-number "~0.0.6"
2493 |
2494 | tar@~2.2.1:
2495 | version "2.2.1"
2496 | resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
2497 | dependencies:
2498 | block-stream "*"
2499 | fstream "^1.0.2"
2500 | inherits "2"
2501 |
2502 | text-table@~0.2.0:
2503 | version "0.2.0"
2504 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
2505 |
2506 | through@^2.3.6, through@~2.3, through@~2.3.1, through@2:
2507 | version "2.3.8"
2508 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
2509 |
2510 | timed-out@^2.0.0:
2511 | version "2.0.0"
2512 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-2.0.0.tgz#f38b0ae81d3747d628001f41dafc652ace671c0a"
2513 |
2514 | to-fast-properties@^1.0.1:
2515 | version "1.0.2"
2516 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320"
2517 |
2518 | touch@1.0.0:
2519 | version "1.0.0"
2520 | resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de"
2521 | dependencies:
2522 | nopt "~1.0.10"
2523 |
2524 | tough-cookie@~2.3.0:
2525 | version "2.3.2"
2526 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a"
2527 | dependencies:
2528 | punycode "^1.4.1"
2529 |
2530 | tryit@^1.0.1:
2531 | version "1.0.3"
2532 | resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
2533 |
2534 | tunnel-agent@~0.4.1:
2535 | version "0.4.3"
2536 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
2537 |
2538 | tweetnacl@^0.14.3, tweetnacl@~0.14.0:
2539 | version "0.14.3"
2540 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.3.tgz#3da382f670f25ded78d7b3d1792119bca0b7132d"
2541 |
2542 | type-check@~0.3.2:
2543 | version "0.3.2"
2544 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
2545 | dependencies:
2546 | prelude-ls "~1.1.2"
2547 |
2548 | type-is@~1.6.13:
2549 | version "1.6.13"
2550 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.13.tgz#6e83ba7bc30cd33a7bb0b7fb00737a2085bf9d08"
2551 | dependencies:
2552 | media-typer "0.3.0"
2553 | mime-types "~2.1.11"
2554 |
2555 | typedarray@~0.0.5:
2556 | version "0.0.6"
2557 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
2558 |
2559 | uid-number@~0.0.6:
2560 | version "0.0.6"
2561 | resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
2562 |
2563 | undefsafe@0.0.3:
2564 | version "0.0.3"
2565 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f"
2566 |
2567 | unpipe@~1.0.0, unpipe@1.0.0:
2568 | version "1.0.0"
2569 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
2570 |
2571 | update-notifier@0.5.0:
2572 | version "0.5.0"
2573 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-0.5.0.tgz#07b5dc2066b3627ab3b4f530130f7eddda07a4cc"
2574 | dependencies:
2575 | chalk "^1.0.0"
2576 | configstore "^1.0.0"
2577 | is-npm "^1.0.0"
2578 | latest-version "^1.0.0"
2579 | repeating "^1.1.2"
2580 | semver-diff "^2.0.0"
2581 | string-length "^1.0.0"
2582 |
2583 | user-home@^1.1.1:
2584 | version "1.1.1"
2585 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
2586 |
2587 | user-home@^2.0.0:
2588 | version "2.0.0"
2589 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
2590 | dependencies:
2591 | os-homedir "^1.0.0"
2592 |
2593 | util-deprecate@~1.0.1:
2594 | version "1.0.2"
2595 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
2596 |
2597 | utils-merge@1.0.0:
2598 | version "1.0.0"
2599 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
2600 |
2601 | uuid@^2.0.1:
2602 | version "2.0.3"
2603 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
2604 |
2605 | v8flags@^2.0.10:
2606 | version "2.0.11"
2607 | resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881"
2608 | dependencies:
2609 | user-home "^1.1.1"
2610 |
2611 | vary@^1, vary@~1.1.0:
2612 | version "1.1.0"
2613 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140"
2614 |
2615 | verror@1.3.6:
2616 | version "1.3.6"
2617 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c"
2618 | dependencies:
2619 | extsprintf "1.0.2"
2620 |
2621 | wide-align@^1.1.0:
2622 | version "1.1.0"
2623 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad"
2624 | dependencies:
2625 | string-width "^1.0.1"
2626 |
2627 | winston@^2.3.0:
2628 | version "2.3.0"
2629 | resolved "https://registry.yarnpkg.com/winston/-/winston-2.3.0.tgz#207faaab6fccf3fe493743dd2b03dbafc7ceb78c"
2630 | dependencies:
2631 | async "~1.0.0"
2632 | colors "1.0.x"
2633 | cycle "1.0.x"
2634 | eyes "0.1.x"
2635 | isstream "0.1.x"
2636 | stack-trace "0.0.x"
2637 |
2638 | wordwrap@~1.0.0:
2639 | version "1.0.0"
2640 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
2641 |
2642 | wrappy@1:
2643 | version "1.0.2"
2644 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
2645 |
2646 | write-file-atomic@^1.1.2:
2647 | version "1.2.0"
2648 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.2.0.tgz#14c66d4e4cb3ca0565c28cf3b7a6f3e4d5938fab"
2649 | dependencies:
2650 | graceful-fs "^4.1.2"
2651 | imurmurhash "^0.1.4"
2652 | slide "^1.1.5"
2653 |
2654 | write@^0.2.1:
2655 | version "0.2.1"
2656 | resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
2657 | dependencies:
2658 | mkdirp "^0.5.1"
2659 |
2660 | x-xss-protection@1.0.0:
2661 | version "1.0.0"
2662 | resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.0.0.tgz#898afb93869b24661cf9c52f9ee8db8ed0764dd9"
2663 |
2664 | xdg-basedir@^2.0.0:
2665 | version "2.0.0"
2666 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2"
2667 | dependencies:
2668 | os-homedir "^1.0.0"
2669 |
2670 | xtend@^4.0.0:
2671 | version "4.0.1"
2672 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
2673 |
2674 |
--------------------------------------------------------------------------------