From 8acfa8f346a4e74c47717a8d40009e45b5a587e1 Mon Sep 17 00:00:00 2001 From: Michael Warkentin Date: Wed, 13 Jul 2016 12:46:32 -0600 Subject: [PATCH 01/24] Switch API call for `instances terminate` Convox is currently using the ec2 terminate instances call - this doesn't take autoscaling events or containers into account. Switch to `TerminateInstanceInAutoScalingGroup` instead. --- api/controllers/instances.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/controllers/instances.go b/api/controllers/instances.go index 5f9b575168..83b70e9148 100644 --- a/api/controllers/instances.go +++ b/api/controllers/instances.go @@ -70,8 +70,9 @@ func InstanceTerminate(rw http.ResponseWriter, r *http.Request) *httperr.Error { instanceId := mux.Vars(r)["id"] - _, err = models.EC2().TerminateInstances(&ec2.TerminateInstancesInput{ - InstanceIds: []*string{&instanceId}, + _, err = models.AutoScaling().TerminateInstanceInAutoScalingGroup(&autoscaling.TerminateInstanceInAutoScalingGroupInput{ + InstanceId: aws.String(instanceId), + ShouldDecrementDesiredCapacity: aws.Bool(false), }) if err != nil { From 69d5a174aa665f957f2704ae767b24f8e957bfde Mon Sep 17 00:00:00 2001 From: Matthew Manning Date: Mon, 27 Jun 2016 03:49:05 -0400 Subject: [PATCH 02/24] export LabelsByPrefix --- api/manifest/manifest.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/manifest/manifest.go b/api/manifest/manifest.go index a6a02388dc..a77636f372 100644 --- a/api/manifest/manifest.go +++ b/api/manifest/manifest.go @@ -191,7 +191,7 @@ func (m Manifest) Validate() error { regexValidCronLabel := regexp.MustCompile(`\A[a-zA-Z][-a-zA-Z0-9]{3,29}\z`) for _, entry := range map[string]ManifestEntry(m) { - labels := entry.labelsByPrefix("convox.cron") + labels := entry.LabelsByPrefix("convox.cron") for k := range labels { parts := strings.Split(k, ".") if len(parts) != 3 { @@ -998,7 +998,7 @@ func (me ManifestEntry) Label(key string) string { return "" } -func (me ManifestEntry) labelsByPrefix(prefix string) map[string]string { +func (me ManifestEntry) LabelsByPrefix(prefix string) map[string]string { returnLabels := make(map[string]string) switch labels := me.Labels.(type) { case map[interface{}]interface{}: From 58b83cb1681e304b4730b009418550f9dbea82b4 Mon Sep 17 00:00:00 2001 From: Matthew Manning Date: Mon, 27 Jun 2016 03:49:48 -0400 Subject: [PATCH 03/24] honor volumes if convox.volumes.mount label is set --- api/models/manifest.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/api/models/manifest.go b/api/models/manifest.go index 07a305c661..0f972b9b9c 100644 --- a/api/models/manifest.go +++ b/api/models/manifest.go @@ -469,10 +469,19 @@ func (me ManifestEntry) EnvMap() map[string]string { } func (me ManifestEntry) MountableVolumes() []string { + volumesEnabled := false + labels := me.LabelsByPrefix("convox.volumes.mount") + for _, value := range labels { + if value == "true" { + volumesEnabled = true + break + } + } + volumes := []string{} for _, volume := range me.Volumes { - if strings.HasPrefix(volume, "/var/run/docker.sock") { + if strings.HasPrefix(volume, "/var/run/docker.sock") || volumesEnabled { volumes = append(volumes, volume) } } From 8826b44b7c08e534595b22a662199c81336bd335 Mon Sep 17 00:00:00 2001 From: Matthew Manning Date: Mon, 27 Jun 2016 11:08:18 -0400 Subject: [PATCH 04/24] comment LabelsByPrefix func --- api/manifest/manifest.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/manifest/manifest.go b/api/manifest/manifest.go index a77636f372..baeb172b87 100644 --- a/api/manifest/manifest.go +++ b/api/manifest/manifest.go @@ -998,6 +998,8 @@ func (me ManifestEntry) Label(key string) string { return "" } +// LabelsByPrefix filters Docker Compose label names by prefixes and returns +// a map of label names to values that match. func (me ManifestEntry) LabelsByPrefix(prefix string) map[string]string { returnLabels := make(map[string]string) switch labels := me.Labels.(type) { From 07f3932232f6c64d1cb3719a15a45bf1f6eb44eb Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 29 Jun 2016 10:10:00 -0400 Subject: [PATCH 05/24] use efs to back docker volumes --- api/dist/kernel.json | 51 ++++++++++++++++++++++++++++++++++++++++++ api/models/manifest.go | 43 ++++++++++++++++++++++++++--------- 2 files changed, 83 insertions(+), 11 deletions(-) diff --git a/api/dist/kernel.json b/api/dist/kernel.json index f96f2517fe..6e2d2b714a 100644 --- a/api/dist/kernel.json +++ b/api/dist/kernel.json @@ -897,6 +897,15 @@ "bootcmd:\n", " - mkswap /dev/xvdb\n", " - swapon /dev/xvdb\n", + " - yum install -y nfs-utils\n", + " - mkdir /volumes\n", + { "Fn::Join": [ "", [ + " - mount -t nfs -o nfsvers=4.1 $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).", + { "Ref": "VolumeFilesystem" }, + ".efs.", + { "Ref": "AWS::Region" }, + ".amazonaws.com:/ /volumes\n" + ] ] }, " - [ cloud-init-per, instance, docker_storage_setup, /usr/bin/docker-storage-setup ]\n", " - echo ECS_CLUSTER=", { "Ref": "Cluster" }, " >> /etc/ecs/ecs.config\n", " - echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config\n", @@ -1437,6 +1446,48 @@ "ProvisionedThroughput": { "ReadCapacityUnits": "5", "WriteCapacityUnits": "5" } } }, + "VolumeFilesystem": { + "Type": "AWS::EFS::FileSystem", + "Properties": { + "FileSystemTags": [ + { "Key": "Name", "Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "volumes" ] ] } } + ] + } + }, + "VolumeSecurity": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "volume security group", + "SecurityGroupIngress": [ + { "IpProtocol": "tcp", "FromPort": "2049", "ToPort": "2049", "CidrIp": { "Ref": "VPCCIDR" } } + ], + "VpcId": { "Ref": "Vpc" } + } + }, + "VolumeTarget0": { + "Type": "AWS::EFS::MountTarget", + "Properties": { + "FileSystemId": { "Ref": "VolumeFilesystem" }, + "SubnetId": { "Ref": "Subnet0" }, + "SecurityGroups": [ { "Ref": "VolumeSecurity" } ] + } + }, + "VolumeTarget1": { + "Type": "AWS::EFS::MountTarget", + "Properties": { + "FileSystemId": { "Ref": "VolumeFilesystem" }, + "SubnetId": { "Ref": "Subnet1" }, + "SecurityGroups": [ { "Ref": "VolumeSecurity" } ] + } + }, + "VolumeTarget2": { + "Type": "AWS::EFS::MountTarget", + "Properties": { + "FileSystemId": { "Ref": "VolumeFilesystem" }, + "SubnetId": { "Ref": "Subnet2" }, + "SecurityGroups": [ { "Ref": "VolumeSecurity" } ] + } + }, "Settings": { "Properties": { "AccessControl": "Private", diff --git a/api/models/manifest.go b/api/models/manifest.go index 0f972b9b9c..251b0c11c6 100644 --- a/api/models/manifest.go +++ b/api/models/manifest.go @@ -7,6 +7,7 @@ import ( "html/template" "math/rand" "os" + "path/filepath" "sort" "strings" @@ -468,21 +469,41 @@ func (me ManifestEntry) EnvMap() map[string]string { return envs } -func (me ManifestEntry) MountableVolumes() []string { - volumesEnabled := false - labels := me.LabelsByPrefix("convox.volumes.mount") - for _, value := range labels { - if value == "true" { - volumesEnabled = true - break - } - } +// TODO: remove when default +func (me ManifestEntry) MountVolumes() bool { + return me.Label("convox.volumes.mount") == "true" +} +func (me ManifestEntry) MountableVolumes() []string { volumes := []string{} for _, volume := range me.Volumes { - if strings.HasPrefix(volume, "/var/run/docker.sock") || volumesEnabled { - volumes = append(volumes, volume) + parts := strings.Split(volume, ":") + + // if only one volume part use it for both sides + if len(parts) == 1 { + parts = append(parts, parts[0]) + } + + // if we dont have two volume parts bail + if len(parts) != 2 { + continue + } + + // only support absolute paths for volume source + if !filepath.IsAbs(parts[0]) { + continue + } + + // special case for docker socket + if parts[0] == "/var/run/docker.sock" { + volumes = append(volumes, fmt.Sprintf("%s:%s", parts[0], parts[1])) + continue + } + + // mount the rest on the efs volume + if me.MountVolumes() { + volumes = append(volumes, fmt.Sprintf("/volumes%s:%s", parts[0], parts[1])) } } From db9d83469a041934e055c27e1cdac51248632333 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 29 Jun 2016 10:15:28 -0400 Subject: [PATCH 06/24] fix comment --- api/models/manifest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/models/manifest.go b/api/models/manifest.go index 251b0c11c6..976e696197 100644 --- a/api/models/manifest.go +++ b/api/models/manifest.go @@ -469,7 +469,7 @@ func (me ManifestEntry) EnvMap() map[string]string { return envs } -// TODO: remove when default +// Returns true if we should try to mount the volumes for this entry func (me ManifestEntry) MountVolumes() bool { return me.Label("convox.volumes.mount") == "true" } From e6a49db3044dd227656a061c4bd2497d9da4f316 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 29 Jun 2016 11:33:38 -0400 Subject: [PATCH 07/24] always mount volumes --- api/models/manifest.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/api/models/manifest.go b/api/models/manifest.go index 976e696197..8234964673 100644 --- a/api/models/manifest.go +++ b/api/models/manifest.go @@ -469,11 +469,6 @@ func (me ManifestEntry) EnvMap() map[string]string { return envs } -// Returns true if we should try to mount the volumes for this entry -func (me ManifestEntry) MountVolumes() bool { - return me.Label("convox.volumes.mount") == "true" -} - func (me ManifestEntry) MountableVolumes() []string { volumes := []string{} @@ -502,9 +497,7 @@ func (me ManifestEntry) MountableVolumes() []string { } // mount the rest on the efs volume - if me.MountVolumes() { - volumes = append(volumes, fmt.Sprintf("/volumes%s:%s", parts[0], parts[1])) - } + volumes = append(volumes, fmt.Sprintf("/volumes%s:%s", parts[0], parts[1])) } return volumes From 7a15433a2cdbfd7684733d533306aecb5e04f4ac Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 29 Jun 2016 11:40:24 -0400 Subject: [PATCH 08/24] only use efs in regions where it is supported --- api/dist/kernel.json | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/api/dist/kernel.json b/api/dist/kernel.json index 6e2d2b714a..73e4c4a8d3 100644 --- a/api/dist/kernel.json +++ b/api/dist/kernel.json @@ -11,7 +11,14 @@ "BlankRegistryHost": { "Fn::Equals": [ { "Ref": "RegistryHost" }, "" ] }, "Development": { "Fn::Equals": [ { "Ref": "Development" }, "Yes" ] }, "Private": { "Fn::Equals": [ { "Ref": "Private" }, "Yes" ] }, - "PrivateApi": { "Fn::Equals": [ { "Ref": "PrivateApi" }, "Yes" ] } + "PrivateApi": { "Fn::Equals": [ { "Ref": "PrivateApi" }, "Yes" ] }, + "RegionHasEFS": { + "Fn::Or": [ + { "Fn::Equals": [ { "Ref": "AWS::Region" }, "us-east-1" ]}, + { "Fn::Equals": [ { "Ref": "AWS::Region" }, "us-west-2" ]}, + { "Fn::Equals": [ { "Ref": "AWS::Region" }, "eu-west-1" ]} + ] + } }, "Mappings": { "RegionConfig": { @@ -899,13 +906,16 @@ " - swapon /dev/xvdb\n", " - yum install -y nfs-utils\n", " - mkdir /volumes\n", - { "Fn::Join": [ "", [ - " - mount -t nfs -o nfsvers=4.1 $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).", - { "Ref": "VolumeFilesystem" }, - ".efs.", - { "Ref": "AWS::Region" }, - ".amazonaws.com:/ /volumes\n" - ] ] }, + { "Fn::If": [ "RegionHasEFS", + { "Fn::Join": [ "", [ + " - mount -t nfs -o nfsvers=4.1 $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).", + { "Ref": "VolumeFilesystem" }, + ".efs.", + { "Ref": "AWS::Region" }, + ".amazonaws.com:/ /volumes\n" + ] ] }, + "" + ] }, " - [ cloud-init-per, instance, docker_storage_setup, /usr/bin/docker-storage-setup ]\n", " - echo ECS_CLUSTER=", { "Ref": "Cluster" }, " >> /etc/ecs/ecs.config\n", " - echo ECS_ENGINE_AUTH_TYPE=docker >> /etc/ecs/ecs.config\n", @@ -1448,6 +1458,7 @@ }, "VolumeFilesystem": { "Type": "AWS::EFS::FileSystem", + "Condition": "RegionHasEFS", "Properties": { "FileSystemTags": [ { "Key": "Name", "Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "volumes" ] ] } } @@ -1456,6 +1467,7 @@ }, "VolumeSecurity": { "Type": "AWS::EC2::SecurityGroup", + "Condition": "RegionHasEFS", "Properties": { "GroupDescription": "volume security group", "SecurityGroupIngress": [ @@ -1466,6 +1478,7 @@ }, "VolumeTarget0": { "Type": "AWS::EFS::MountTarget", + "Condition": "RegionHasEFS", "Properties": { "FileSystemId": { "Ref": "VolumeFilesystem" }, "SubnetId": { "Ref": "Subnet0" }, @@ -1474,6 +1487,7 @@ }, "VolumeTarget1": { "Type": "AWS::EFS::MountTarget", + "Condition": "RegionHasEFS", "Properties": { "FileSystemId": { "Ref": "VolumeFilesystem" }, "SubnetId": { "Ref": "Subnet1" }, @@ -1482,6 +1496,7 @@ }, "VolumeTarget2": { "Type": "AWS::EFS::MountTarget", + "Condition": "RegionHasEFS", "Properties": { "FileSystemId": { "Ref": "VolumeFilesystem" }, "SubnetId": { "Ref": "Subnet2" }, From d5b527010eae47f75de5e5c6f515d259bef93864 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 29 Jun 2016 23:01:59 -0400 Subject: [PATCH 09/24] namespace mounted volumes with app stack and process name --- api/models/manifest.go | 21 +++++++++++---------- api/models/templates.go | 18 +++++++++--------- api/models/templates/app.tmpl | 8 ++++++-- api/provider/aws/templates.go | 2 +- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/api/models/manifest.go b/api/models/manifest.go index 8234964673..3f479574fc 100644 --- a/api/models/manifest.go +++ b/api/models/manifest.go @@ -469,8 +469,13 @@ func (me ManifestEntry) EnvMap() map[string]string { return envs } -func (me ManifestEntry) MountableVolumes() []string { - volumes := []string{} +type MountableVolume struct { + Host string + Container string +} + +func (me ManifestEntry) MountableVolumes() []MountableVolume { + volumes := []MountableVolume{} for _, volume := range me.Volumes { parts := strings.Split(volume, ":") @@ -490,14 +495,10 @@ func (me ManifestEntry) MountableVolumes() []string { continue } - // special case for docker socket - if parts[0] == "/var/run/docker.sock" { - volumes = append(volumes, fmt.Sprintf("%s:%s", parts[0], parts[1])) - continue - } - - // mount the rest on the efs volume - volumes = append(volumes, fmt.Sprintf("/volumes%s:%s", parts[0], parts[1])) + volumes = append(volumes, MountableVolume{ + Host: parts[0], + Container: parts[1], + }) } return volumes diff --git a/api/models/templates.go b/api/models/templates.go index 1ba65957ae..690d4881de 100644 --- a/api/models/templates.go +++ b/api/models/templates.go @@ -75,7 +75,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _templatesAppTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xec\x3c\x6b\x73\xdb\x46\x92\x9f\xcf\xbf\x62\x0a\x95\x2a\x2a\x09\x45\x3d\xbc\x9b\xdb\x63\xce\x5b\x25\x53\x74\xac\xac\x5e\x47\xd2\xde\xba\xd8\x2a\x17\x04\x0e\x45\x44\x20\xc0\xe0\xa1\x47\x54\xfc\xef\xd7\x3d\x0f\x60\x5e\x20\x20\x8a\xf6\xdd\xd5\x9d\x76\x93\x10\x98\x9e\x9e\x9e\x9e\x9e\x9e\x7e\x0d\x9e\x9e\xc8\x94\xce\xc2\x98\x12\xcf\x5f\x2e\x3d\xb2\x5a\xbd\x22\xe4\x09\xfe\x21\xc4\x3b\xfa\xe7\x78\x42\x17\xcb\xc8\xcf\xe9\xbb\x24\x5d\xf8\xf9\x47\x9a\x66\x61\x12\x7b\xa4\x4f\xbc\xc3\xfd\x83\xfd\xdd\xfd\x7f\x83\xff\x7b\x5d\x0e\x3e\x48\xe2\x69\x98\x43\x7b\xe6\xf5\x05\x0a\x40\xf5\x44\x72\x81\x83\x78\xd7\x7e\xe4\xc7\x01\x4d\x77\x83\x0a\x94\xf4\xf8\x98\x16\xf0\x32\x4d\x02\x9a\x65\xad\x60\x53\x7a\x13\x66\x79\xfa\x58\x07\xec\x5d\xa6\xe1\x1d\x40\x22\x61\xc4\x7b\x17\xf7\xfb\xc3\x3f\x0a\x3f\x42\x42\x3f\xe1\x9b\x11\x9d\xc1\xcf\x12\x8a\xac\xba\xc4\xfb\x4f\x0a\x38\xae\xe0\xa7\xc4\xf1\x16\x88\xbf\x1d\xd3\xa0\x48\xc3\xfc\xf1\x97\x34\x29\x96\xc8\x88\x27\x15\x1d\x3c\x7f\x7a\x62\xd8\x90\x45\x3a\x2c\xe2\xf4\xae\x38\x45\x02\xa9\x77\xe9\xa7\xfe\x82\xe6\xc0\x56\x86\x6a\x2d\xcf\x96\x08\xdb\x82\x5f\x1a\x9c\xa4\x7d\x10\x15\x19\x0c\xa3\x2c\x0c\xbc\x9c\x3c\x2e\x29\x27\x34\x4f\xc3\xf8\xc6\xeb\x56\x4d\xc7\x74\xe6\x17\x51\xce\x5a\xf5\xf7\x59\x90\x86\xcb\x5c\x4a\x81\x27\x9a\x2a\x2e\x1d\xd3\x65\x94\x3c\x2e\x68\x9c\x9f\xf9\x0f\xe1\xa2\x58\x38\xc6\x84\x8e\xe7\xc5\xe2\x1a\xe8\x71\x0c\xc9\x64\x6b\xbf\x6e\x50\x68\x15\x78\xc9\x92\xa6\x01\x0c\xe3\xdf\x50\x92\xcc\x88\x98\x3e\xcd\x48\x9e\x90\x5b\x4a\x97\x24\x2d\xe2\x18\xa6\x45\xee\xe7\x61\x44\x41\xca\x91\x2e\x9c\xe6\x3a\x92\xc3\x78\x43\x92\x0f\xd6\x93\xcc\xf1\x6e\x8f\xe4\x61\x7c\x17\xa6\x49\x8c\x34\xbb\x89\xad\x5f\xd2\x35\x2b\xea\x5c\xd0\x7f\xd0\xc7\xaf\x3d\x84\xb2\x3b\xdb\x0d\xa3\xe1\x1b\xa4\x14\x37\x40\x18\x83\x80\xc7\x7e\x44\xa2\xc4\x9f\x12\xb9\x6d\x32\x78\x0f\x8c\x66\xf8\x49\x56\x5c\xc7\x34\xcf\x6a\x48\x3e\x4f\xd4\x86\xa3\x28\x4a\xee\xe9\xf4\xa3\x1f\x15\x94\xeb\x09\xa6\x11\xba\x0c\x8e\x5c\x59\x73\x18\xd1\x88\xfa\x99\x6b\x0e\xdb\xde\x61\x23\xba\x4c\xb2\x30\x4f\x52\xd7\xba\xbc\x6c\xb0\x71\x52\x80\x80\x92\x20\x99\x52\x92\x56\xc3\x58\x24\xe8\x9a\x6d\xdb\x54\x4c\xe6\x94\x9c\xaa\x8b\x48\x32\x31\x1e\xb9\xc1\x01\xc9\x2c\x49\x49\x3e\x0f\x33\x82\x47\x96\x4d\x9c\x58\x65\x37\x59\xa7\x70\x50\xfc\x3b\x9c\x6c\xa0\xb3\x07\x87\xfd\x3e\x07\xee\xf7\x4f\xa6\x7f\xdf\x84\xd4\x8f\x97\x03\x29\x55\xed\xa8\xaa\x17\xf5\xaf\x43\x9c\x21\xfa\x0d\x44\xca\x03\x5e\xa3\xce\xd8\x6e\x3b\xa3\xe1\x7f\x7c\x38\x19\x0d\x8f\xbf\x27\xa7\xfe\xe2\x7a\xea\x93\x01\x9c\x2d\xc9\x62\x92\x2c\xc3\x80\xbc\xf7\xe3\x69\x04\x2b\x26\xb6\x03\x91\x18\x15\x32\x41\x19\x9e\xd2\xf8\x26\x9f\x33\x22\x0f\xd4\x26\x63\xcf\xdb\xf4\x5d\x0e\x6a\x38\x57\x31\x0d\x60\x90\x63\x9b\x32\xac\x81\x41\x97\x83\xc1\xc9\xf1\x68\xeb\x22\x8f\x23\x23\x62\xf7\xf0\x9a\xcd\x70\x06\x2d\x30\x8a\x2a\xdf\xde\x65\x92\xe6\x97\x69\x92\x27\x41\x12\xe9\xb4\xcd\xf3\x7c\xc9\xad\x1e\x94\x2d\x1a\xd3\x54\x81\xf3\xde\x4f\x26\x97\xa8\xd2\x4e\xe2\x2c\xc7\x9d\xe6\x6a\x63\x7b\x9d\xd6\x41\x8c\xbd\x8a\x3b\x62\xb8\x6c\xfd\x78\xe3\x17\x0f\xa8\x8d\x98\x07\x6b\xe6\x37\x19\xd4\x4e\x4f\x34\xd5\x0f\x36\x1e\x9f\x9a\x43\x45\x6b\xa6\x86\xe0\x2f\x1b\x8a\xac\x9c\xeb\x3d\xa2\x19\xd3\xca\xda\x82\x2b\x5b\x6e\x94\x44\x35\x27\x27\xdb\x13\x27\x47\x67\xfd\x3e\x83\x51\x66\x02\x83\x83\x29\x92\x87\x54\xd7\x92\x78\xec\x65\x59\xb1\xa0\x08\x7f\x99\x44\x61\xf0\x78\x9c\x04\x85\x65\x65\xf0\xad\x50\xea\x0a\xf4\x05\x0e\x77\xc1\x1d\x38\xf8\x57\x65\x10\x06\x34\xce\x41\xf9\x88\xfe\x9f\xb4\x26\x62\xe0\x63\xe0\xc3\xd9\x8c\x06\xec\x30\x66\xc7\xaf\x81\x4d\x90\x1e\xc6\x41\xb8\xf4\x23\xbe\x14\x63\x9a\xde\x85\x01\xe5\x07\x74\xc4\xf4\x51\xcf\x5f\xf8\x7f\x26\xb1\x7f\x9f\xf5\x82\x64\xa1\xd9\xf0\xea\x44\x03\xa1\xd0\xa0\x5f\x96\x67\xfd\x6a\xe2\xd5\xe9\x2e\xff\x56\xda\xb3\xda\xaa\x61\x06\x73\x1e\x94\x1a\x10\xbf\xe7\xe9\xaf\x91\x93\x9c\xd7\x3a\x0f\x4c\x0e\x70\xc8\xc7\x73\xf0\x09\x18\x0f\xa6\x0b\xb0\x1b\xc1\xaf\xf1\xe1\x14\xb6\x78\xe1\x35\x2c\x10\x83\x69\xb3\x48\x0c\x50\x5b\x28\x64\xac\xb5\x14\x0a\xcb\xbc\x1f\xf0\x51\x0a\x26\x7f\x41\x56\x0d\x6c\x53\x9f\x2a\xc8\x95\xa5\x62\x15\xd1\x5e\x23\xd6\xfc\xe8\xe9\xf7\xdf\x15\x31\xa7\xaa\x95\x74\x0f\xc0\xb0\xb1\x25\x79\xfc\xfa\x6d\x11\xdc\xd2\xbc\xf2\x0e\x7f\x4d\x42\x21\x1a\xbb\x30\x53\xf8\x0f\xf8\x95\x77\xc9\x03\xfc\xae\x9c\x45\x46\xc6\x08\x1c\x4f\x54\xe1\x30\x79\x5b\xce\x00\xb1\x30\x9e\x4d\xac\x1c\x69\xca\xcf\xc8\x3d\x0d\x6d\xe9\x63\xa3\xbf\xb8\x37\x63\x7e\x37\x3c\xf7\xfe\x0c\x97\x1e\x1f\xa4\x56\xfc\xc4\xd9\x8b\x58\xc4\x4e\xa0\x0f\xdc\x26\xd6\xe5\xf1\x8c\x2e\xc0\xaa\x1b\x87\x7f\x32\x76\x1e\x1c\xfe\x4d\x6f\x96\x0a\x85\x13\xfd\x0b\xcd\x8f\x72\x2e\x15\x96\xd6\x41\x99\x48\x63\x6b\x87\x79\xa3\x22\xce\x43\x2e\xc3\x31\x70\xfc\xf7\x4c\x1f\x60\x02\x6d\x49\xc1\x64\xeb\xf5\xbe\x57\x2f\x0a\x6e\x3f\x38\x2d\xf5\x61\xad\x2b\x1c\x80\x6b\xf4\x7b\x72\xdd\x06\x54\x7a\xcd\xcf\x00\xcd\xb8\xca\x69\x13\x8e\x30\xb1\xba\x80\xa5\x6d\xeb\xd5\x20\xcb\x72\x1e\x92\xd0\x4f\x85\x8b\x22\x5f\x16\x79\x73\xa4\x25\x11\x70\x8d\xb3\x6a\x04\x2c\x27\xa5\x43\x56\x2e\x41\x9e\x1b\x66\x09\xea\x1f\x74\x9f\xb8\x30\x09\xf9\x2e\xe1\xcc\xe3\xee\x15\xfe\x03\x23\xd2\x78\xca\xf0\x2a\x91\x29\x57\x28\x88\x07\xaa\x9e\x48\xea\xc7\xe0\x4d\x7f\x77\x4b\xfa\x6f\x48\x6f\x18\x03\x81\xa8\x3e\x33\x39\x09\x1e\xb5\x01\xb8\x62\x09\x3a\x01\xe1\x56\xab\xea\xcc\xb0\x83\x41\xb8\x35\x3d\x45\xa2\xc1\xd3\xf6\xaf\x23\x3a\xd5\x31\x54\x5d\xcf\x13\xb6\x37\x9c\x51\x25\x7c\x33\x86\x3d\x1e\xf0\xed\xb3\xaf\x6e\x73\x1d\xdf\x3b\xb9\xcd\xb9\x26\xc1\xad\xbf\x7b\xc0\xa8\x10\x84\x54\x7c\x59\xcf\x21\x19\xfc\x31\xb8\x43\x19\x77\x4a\x9e\x54\x83\xd3\x1e\x72\x4b\xa3\x40\xb1\x32\xa4\xc6\x1d\x24\x8b\x85\x7f\x4c\xa3\x70\x11\xe6\x74\x8a\xd6\x8f\xa7\x04\x4f\xaa\x18\x48\x77\xbf\x7b\xf8\xd7\x9f\xd4\x36\xcd\x73\xe0\x01\x14\x2b\xf2\x91\x16\x71\x97\x0c\x2e\x3f\x90\x22\x0e\x73\xfe\x86\xe2\x1e\xa3\x5d\x02\x0a\x8d\x9c\xbd\xc5\x1e\xa3\xa3\x33\xa5\xc5\xab\xf6\x42\x5b\xce\x94\x52\xcb\x98\xe0\x9d\x26\x37\xba\xf3\xea\x10\xd5\x12\x86\x0b\x67\xb7\x61\x04\x65\xb3\xd7\x8d\xa1\x1f\x61\xc9\x4d\xc6\xfe\xcd\x81\xda\x0c\x51\xa9\x1e\xb9\xc0\xdf\x2d\xfc\x38\x9c\xd1\x2c\x57\x56\x18\x5e\x87\x33\xd2\x7b\xef\x83\xb7\x29\xf9\x2c\x96\xbe\x4e\x24\xdc\x42\x31\x1c\x8c\x27\x7e\x76\x7b\x8c\x54\x84\xb9\xc3\x31\x5c\x02\xad\xd9\x05\x3b\xd4\xb4\x73\xbb\x5b\x1a\x66\xec\x9c\xb8\x72\xb8\x78\x1c\x1c\x7d\x36\x73\x0c\x05\x58\x31\x5f\x0e\x7a\xfb\xed\xce\x78\x31\xf0\x24\xb9\xa5\x71\xe3\x31\x56\x7b\x84\x09\x1b\xac\xc6\x1e\x30\xac\x00\x30\x9e\x82\x5b\xd6\x83\x6d\x5d\x5c\x96\x92\x87\x9e\x6d\x19\xa8\xb1\xa2\x12\x91\x7c\x67\x80\x1a\x81\xbe\x12\x5c\x7d\x6f\x74\x29\x6d\x0e\x01\x8a\xcf\x06\x08\x72\x5c\xa8\x29\x55\xc5\x53\x54\x9f\x5f\x72\x68\xe4\xca\x7d\xad\x9d\xe6\x96\x17\x45\xb7\x56\x8b\x55\x66\x06\x38\xe5\x86\x42\xad\x58\xd5\xad\x91\x2d\x85\x74\x2e\xdb\xd0\x07\xa4\xfb\xad\x0c\x0f\xad\x74\x4b\xd3\x53\xf7\x45\x4f\x42\x49\x73\x95\x0d\xe6\x1c\x54\x55\x26\x0a\x36\x4d\x5c\x1c\x92\xc6\x44\xbc\x7a\xdf\x20\xec\x92\x41\xff\x23\xa4\x5c\x49\x0b\x94\xe2\x22\xdf\x19\xa0\xa0\xcb\xc3\x94\x4e\x07\x49\x11\x2b\x86\x72\xf3\xf1\xe6\x38\x61\xc4\x19\xf7\xcd\xb6\x9b\xad\xc3\xd6\xd1\x69\x2b\x24\x73\xf7\x96\xf6\x71\x69\xd2\x54\x72\x60\x71\xcd\x48\x2d\x5c\xf2\x0c\x80\xd6\xdf\xce\x3f\xd4\x63\xe1\xb9\x8f\x06\x2c\x22\xf1\x62\x60\xc1\x90\xaa\xdc\x0c\x0e\x5f\xb4\x3a\x19\x7a\x18\x4e\x92\x61\x26\x73\x73\x11\x7b\x91\xfa\xc6\x22\x3d\x6b\xfb\x39\x96\x90\xbf\xe8\x81\xd6\xc8\x7d\x38\xfe\x52\xf7\xb2\xba\x77\x2b\x31\x85\xe5\x3c\xe1\x07\x7b\x3b\xff\x53\x45\xd9\x64\x59\x38\xb3\x99\xba\xe1\x55\xce\x5e\x3d\x80\xbf\x2b\xc3\xda\xea\x09\x5c\xf5\x71\x73\xdf\x93\xa8\x2a\x91\x95\x78\x7a\xe2\x98\x17\xfc\xc3\xfe\xc8\x3f\x45\x3d\x02\xc0\x83\x91\x2d\xa8\x4d\x82\x6e\x8e\x5f\x49\x9b\x5a\xa7\xc5\x4b\xa8\xe7\x81\xb3\xaf\x48\xbe\x18\xa0\x96\xfe\x8d\xa4\xc2\x6d\x8a\x6f\x53\x22\x36\x99\xaa\xfc\xb9\x51\x04\xdb\xc0\xf5\xbc\xb4\xd5\x26\xd4\x0e\xf0\xf0\x9b\x85\x41\x7d\xc6\x64\x9b\x89\xb5\x4d\x28\x7c\x9f\x64\xae\x0c\x6c\x2b\x5e\x86\xf1\x94\x3e\x28\x83\x8d\xc0\xdd\x49\x16\xd9\x37\xe6\xb1\x6b\x77\xb5\x9c\x83\x9e\x31\xb5\xc8\x7b\x41\x36\x75\x43\x25\xe4\x48\x80\xb4\x9c\x0a\xc6\xf6\x37\x9f\x0b\xcb\xb2\x74\x65\xfa\xa3\xcb\xb3\x12\x5d\x8e\x75\x7b\xb3\x33\x55\xf8\x7f\xef\x2a\x6d\xa4\x14\x75\x2f\x7c\x13\xad\x68\x9f\x24\x06\xef\x8c\x1d\xb9\xde\xf9\x30\xfa\x56\xa1\x0b\x25\x1a\x60\x1a\xd6\xb8\x30\x9a\x35\xc3\x4d\x96\xe3\xf3\x31\xb7\x49\xaf\xf4\x04\xce\x37\x54\xe3\xeb\xfd\xac\x1a\xec\x9a\x27\x62\xc5\x40\x5e\x44\xdc\x5a\xaf\xf1\xf9\xf8\xa4\x93\xf0\x35\x26\xac\x88\x5b\x4f\x35\x94\x45\x9f\x2d\x88\xbe\x19\x1e\xda\x48\xf8\x1d\xb2\x57\x57\x8b\xf1\x42\xe6\xe8\xb1\x2a\x5e\x8e\xa0\x8d\xa4\x54\xef\x38\x9d\x54\x8f\x81\xe9\x21\x40\xcb\x75\x20\x2d\xfc\xbb\xdd\xeb\x52\x9e\x0c\x27\x40\xaf\x43\x39\x89\x6f\x80\xc7\xa6\x67\xd3\xb4\xfd\x04\x94\xe9\xe3\xf0\x10\xda\x65\x71\x1d\x85\x81\xed\x02\x79\x83\x70\x9a\x9e\x20\xb7\xbd\xfd\x1e\xfb\xdf\xde\xbe\x95\x55\x43\x79\x88\x32\xba\xae\xb7\x92\xf6\x11\x85\x05\x76\xae\xd2\xed\xe5\x00\x96\x93\xa5\x9a\x43\x66\x27\x8e\x09\xf2\x2e\x4d\x16\x38\xed\x6d\x6e\x69\x6b\x90\x49\xb2\xed\x21\xb4\x11\x56\x4d\x01\x9a\x66\x87\x4f\x0d\xc9\x7c\x5c\x06\x27\x53\x93\xf5\x56\x32\xa2\x5b\xbb\xdd\x5c\xf1\x71\xbe\x45\x22\x3f\xcb\xc3\xa0\x52\x1e\x20\x67\x18\xde\xad\x74\x49\xb5\x65\x36\x3b\x93\xb4\x98\x58\x0b\x5d\x50\xcd\xbb\x6e\x8f\x72\x31\xa7\x7f\x90\xde\x38\x98\x53\x40\xe1\xc9\x2a\x3a\xcf\x08\x82\xf1\x76\xb1\xb6\x12\xda\x88\x9e\xa9\x95\x57\x7c\xa3\x9f\xcc\x38\xa9\xb2\xea\xa9\x5b\xe3\xa9\x1b\xc5\x51\x96\xa3\x6f\x02\x1a\xde\xbc\x0a\xef\xdc\x75\x3a\x65\x16\x2e\xbd\xb7\x2e\x5f\xb8\x56\x31\x65\x39\xe6\xe3\xd4\x0f\xb1\x3c\x93\x27\xde\x39\x2e\xb1\x78\xf0\x90\xa7\x05\xed\xaa\xc9\xcd\x9f\xf6\x35\x5d\x55\xe1\x51\x53\x65\xb0\x8d\xa7\x11\xad\x3a\xbd\xfe\x69\xdf\xe8\x96\x26\x59\xf6\x5b\x12\x53\x39\x44\xd5\xf4\x9e\xfa\x51\x3e\x1f\xcc\x69\x70\x6b\x86\x07\x79\xd3\xe3\x64\x0e\x1a\x71\x9e\x44\x48\x9f\x77\xa8\x2f\xd6\x09\xae\xf4\x1d\xab\xa3\xf8\xab\x11\x2e\x4b\x6f\xdc\xc9\x70\x1e\xe8\x11\xf5\x2c\x8e\xdd\x5e\xb3\xc9\xdf\x85\x69\x96\xe3\x83\xb4\xce\x5c\xe9\x72\x85\x71\xaf\xb5\xf7\x1f\xe2\xb9\x73\x32\x55\x08\x47\x61\x89\xac\xcc\xd9\xf0\x14\xd0\xa5\x76\x0b\x31\x0b\x4b\x99\x1b\xcf\x7c\x6b\x96\x6e\x0b\x1f\xff\x1d\x38\x86\x27\x31\x10\x29\x36\x8f\x5a\xdc\xe5\x0e\xb2\x6e\xe0\x24\xb1\xa3\xd5\x2a\x64\xaa\x29\x96\x51\xb5\xd8\xd7\x3e\x4f\x88\xb3\x88\xea\x9b\xb3\xa6\xa6\x5a\xab\x86\x41\x25\xdc\x36\x98\x23\xf6\x88\xab\x4a\x67\x7c\xaa\x84\x44\x8c\x73\xec\xa5\x01\x16\x62\x5a\x18\xb6\x29\xf2\xff\xd2\xfb\xbf\x44\x7a\xff\x6f\xcb\xad\xf6\x7c\xb5\x6d\x0b\xb2\xa6\x9c\xef\x9b\x1f\x31\x3c\x22\xd4\x66\x8f\x6a\x55\x85\xdc\x62\x61\x9d\x2b\xe1\xab\xeb\x24\x2d\x5c\x0d\x5c\x69\x72\x15\x56\xe6\x79\x1a\x5e\x17\x39\x67\x90\x4d\x0e\x03\x92\xc4\x34\x91\xc1\x80\xa5\x93\xee\xa1\xfd\xe3\x59\x30\xab\xab\x06\xc1\xe6\x84\x6c\x43\xb4\xad\x0a\x47\x8b\xfb\x2d\x92\x4f\x5f\x41\x24\x4f\xdf\x0e\x92\xe4\x36\xa4\x63\x70\x40\x6e\xc3\x18\xa6\x52\xda\xa8\x38\x71\x5d\x00\xfc\x19\xcb\x6c\x62\xbe\x46\xc3\x61\x44\x3d\x78\x54\xc4\x15\x0c\xa9\x73\xc0\xc5\xfd\xb7\x52\xc2\xf1\xe9\xd5\xbf\x30\x38\xc7\xdd\xb9\x2e\x6f\xaa\xae\xcb\x35\xfa\x33\x2b\xab\x8b\xd1\x5e\xf1\xa6\x5c\x29\xc5\x9f\x6b\x8a\xd4\x38\xaa\x06\xd5\x72\x1a\x30\xc4\xe3\x5f\x93\xeb\xaa\xb2\x0c\x5f\x94\xe5\xa7\x75\x5e\x61\x6d\x9d\x6a\x6d\xd8\x44\x42\xca\xe5\x62\x6c\xf1\x03\x2c\x13\xdb\xc5\xdf\x47\xcb\xa5\xe0\xce\x2e\x52\xac\x46\xb3\x94\x02\x50\x96\x5b\xe8\xcd\xc5\x0b\x05\xe6\x85\xd5\x9d\x6b\x6b\x3b\x15\x1b\xfe\x60\x5f\x73\x7d\xac\xb2\x5b\xef\xb7\x70\xf9\x2e\x64\xa4\x98\x7e\x86\xf7\x39\x46\x3f\x43\xdb\x31\x5e\xa7\x00\x9f\x2e\x03\xcd\x12\xe4\x9d\x9f\xcd\x2a\x73\xf3\xf9\xce\x4f\x09\x0b\xc5\x93\x37\x24\xa5\x7f\x14\x61\x4a\x77\x3a\xec\x45\xe7\x7b\xab\x33\x02\xfb\xf7\x1a\x28\x3c\xee\x66\xd3\xdb\x1a\xe0\x20\x4a\x8a\x69\x59\x98\x0b\xfd\x62\x7a\x8f\x18\x7a\x03\x6c\x28\xcb\x1c\x76\xdc\xbd\xff\x28\x68\xfa\x98\xb1\x80\xbd\x3a\xa4\xf2\xda\x31\xac\x0b\x11\xcf\x2f\x02\x8e\x27\xb3\x15\xff\x55\xc6\xd0\xfa\xa4\xa3\x48\x50\xc7\x84\x5d\x35\x8e\x25\x6a\xcf\x7a\x34\xbe\xeb\x9d\x5f\x1c\x0f\xbf\x4c\x4e\xc7\x5f\x46\xc3\x5f\x87\x83\xc9\x97\x0f\xe7\x47\x1f\x26\xef\x2f\x46\x27\xbf\x0d\x8f\x81\x92\xce\x7e\xf3\xda\xd0\x87\x25\xaa\x64\x29\x9a\xd0\x6b\x26\x04\x7e\x87\xde\xd1\x38\xef\x92\x20\x01\xcf\xf4\x21\xff\xde\x3d\x31\x68\xcd\x40\x3a\x7b\x51\x72\xb3\xd3\xc1\xab\x48\xc3\xf1\x84\x8c\x86\x83\xe1\xc9\xc7\xe1\x31\x4c\x96\xfc\x48\x7e\x1d\x5f\x9c\xf7\x38\x2f\xc3\xd9\x23\x47\xfb\x7d\x33\x53\x19\x76\x6d\x6d\x7b\x53\x16\xbd\xbc\xa6\x8c\x9b\xd9\x0e\x67\x79\x57\xa1\x38\x4d\xbb\x64\xea\xe7\x7e\x0d\xb1\xf8\x07\xba\x03\xe1\xd6\x40\x98\xd3\x42\x68\x8b\x5a\xf9\x63\xc5\xc3\x1b\x6b\x91\xa1\x78\x4c\xfd\x6c\x7e\x9d\xf8\xe9\xb4\x16\x93\x84\x5c\xfa\x59\x76\x9f\xb4\x00\x14\xc9\x1b\x58\x32\x9c\x72\x8f\x33\xe5\xd3\xfe\x55\x4f\x14\x23\xb7\x18\x49\x5e\x77\xb6\x71\x54\x57\xa1\x5b\x2d\x94\xfc\x83\xb5\xda\x41\xd4\xe1\x9b\xfd\x9f\x25\x81\xbd\x88\x5d\x2f\xfb\x7b\xf8\x33\x09\x7f\xfc\xb1\x81\xf1\xf8\x87\x4b\x24\xfa\x7e\x0a\xe5\x74\xfe\x41\x1f\xc9\x1b\x90\xe9\x63\xc9\xc8\x4e\x0b\x4c\xf8\x57\x72\x1e\x26\x69\x61\x65\xc7\xf8\x5a\x46\xe1\xdf\x6a\x1d\x80\xd5\xd8\xc4\x1f\xc6\x9b\x8a\xf7\x1b\xb1\xa7\xea\x8e\x73\x29\x17\x4b\x32\xe9\x52\xc8\x50\x5b\x1e\x49\x99\x03\x16\xd5\x60\xfe\xd6\x8c\x62\x02\xce\xf2\x14\xb5\x3a\x55\xfd\x9b\x83\x41\xd8\xaf\x96\xba\xdb\x04\x8f\x4a\xaf\x4f\xfe\xf2\x97\xd7\xcd\x90\x7e\x3e\x07\x3d\xb6\x07\x0e\x44\xb6\x87\xea\x8c\xe9\xaf\x1e\x3c\xc2\xef\xce\x5e\x59\x3a\xad\xb4\x89\x77\xac\x3d\x2d\xe2\x4e\xe3\x18\xc0\xe1\x79\x32\x85\x51\x2e\x2f\xc6\x93\x66\xf0\x39\xf5\xa7\xb0\x3e\xfd\x76\x6b\xdb\x39\x0a\x02\xba\xcc\x3b\x80\x1e\x88\x8e\xd0\x49\x03\xae\xee\xfd\x9e\x25\x2d\x28\x63\x08\xb0\xf2\x0b\xe6\xb5\x8b\x96\x94\x89\xe6\x61\xf7\xfe\xfe\x7e\x17\x55\xf4\x6e\x91\x82\x24\xe3\x5d\xe5\x69\x4b\xbc\x1f\x32\x9a\xee\x1e\xdd\x00\x6a\xc4\x0a\xa6\x63\xb4\x67\x1d\x88\x66\xa7\x55\x23\x6a\xbf\x60\x0b\xc6\xaf\x08\xf5\x71\x55\xa4\x74\xaf\x15\xce\x67\xa9\x39\x94\x4e\xb0\x15\x40\x32\x99\x19\xd3\x43\xbb\x81\x66\xf9\x8e\x90\x58\xe5\x48\x02\xeb\xb5\xc5\x1e\x44\x7c\xd7\xc9\xf4\x11\x0f\x6d\xfb\xcc\x36\xa1\xb5\x33\x17\x6f\x8a\x15\x59\xbf\xd3\xc5\x62\xfc\x5e\xc6\x9e\xd0\xc0\xab\x3f\xb2\x9c\x68\xde\x0b\x99\x02\x3c\xc6\x79\x8d\x68\x85\xc4\x39\x4e\x6d\x13\x29\x23\x82\xe6\x43\x14\x04\x40\xb0\xd3\x29\xf2\xd9\xdf\x1c\x26\x94\xab\x1f\xb0\xab\x83\xc7\x50\x47\xe1\x5f\x30\x2f\xe2\x5b\xe0\x20\x67\xcf\x8f\x6f\x08\x7b\x41\x56\xed\x31\x82\x6b\xa1\x22\x6c\xa9\x11\x55\xe6\xe0\xd0\xcd\xe3\x89\x5e\x68\x2b\xf5\xa6\x49\x4c\x1d\x06\xa7\x09\xde\x30\x0b\x47\xf3\x3a\x70\x10\x42\x3e\xe1\x34\x4d\xd2\x8e\x6e\x16\x25\x4d\x06\x8f\x39\xe7\xce\x10\x3b\xa1\x38\xf0\xde\x6d\xa4\x89\x4d\x7d\xe6\x87\xd1\x4e\x8b\x3e\xcf\x9c\x1c\xb3\x57\x40\xc9\x1f\x83\x7c\xc0\x2e\x51\xec\x73\x45\x54\x1b\x66\x08\x3a\x61\xb1\x00\x3b\xb7\x03\xbe\x2a\xd7\xd4\xe2\xc5\x96\x17\xe1\x1e\x7c\x60\xba\x23\xa9\x5d\xcf\x06\x84\x07\x09\x5d\x23\x2c\xce\x33\xd5\x41\x15\x68\x30\xe5\x85\x7e\x35\xd1\x91\x4e\x35\x8a\x26\x44\xac\xcc\xf2\xaa\x59\x7a\x71\x0e\xa7\xa5\x70\x72\x47\x85\x76\xbd\xd9\xc8\xb9\x22\x53\xb3\x7e\x9f\x01\x35\x7a\xd6\xaa\x47\x7d\x9a\xc4\x37\xd2\x8d\xce\x82\x39\x9d\x16\xfa\x0d\xe9\xb1\x78\x37\x7c\x58\x62\x51\x81\x48\xd5\xca\xdc\x27\xb6\x18\x95\x24\x3c\x6b\x66\xc5\xbc\x98\x0b\xed\x76\xb7\xd5\xf0\x41\x5d\x81\x3e\x0b\x95\x9a\x04\x8b\x04\x9d\x91\xcd\x5b\xf2\x1b\x95\x4f\x9f\xf1\x43\x4e\x9f\xe1\xe7\x67\x4f\x0f\x17\x7c\x86\x51\x3e\x4b\x77\xae\x02\x10\xb1\xaf\x12\x40\x88\x68\x05\x30\xe0\x2f\x18\xc0\x4a\x49\xbb\x39\x42\x2c\x8e\xf5\xe3\x01\x90\x4b\x9a\x2e\xc2\x2c\x73\x45\x4a\x88\x19\x2a\x51\x60\x5d\x4b\x4a\xb4\x35\x15\x77\x92\x49\x79\xe7\xb5\x7f\x02\xc7\xf0\x2d\x75\xdd\x0b\xd6\x22\x2b\x64\xc3\x45\x51\x2e\xa0\xe3\xa0\x6c\x5b\x67\xc6\x95\x73\x55\x8e\x58\x28\x89\xa1\xa9\x2d\x26\xb3\xc4\x5d\x19\xf8\xf9\x61\x2c\xe7\xb7\xb0\xf8\x85\x34\x7e\x5b\xf9\xbd\x9f\x8d\x04\x8c\xba\x18\x48\xd9\x45\xaa\x05\xb5\xd7\x7d\x2b\x4b\xbf\xfe\x0c\x14\x17\xd9\x2e\xf5\xb3\x9c\xdd\x5b\x54\x33\xea\xcf\xc4\x71\x0f\x66\xcd\xee\xe1\x0b\x70\xd0\x82\xe3\x60\x74\x08\x14\x28\xaa\xb5\x97\xeb\x5c\xb7\x75\x2b\x7e\x61\x8b\xe3\x8b\x3b\x8e\xab\x3d\x23\x05\x4c\x6c\x06\xad\xce\xc3\xe6\xbe\x80\x72\xde\xff\x71\x6b\xb1\x97\xdf\xfb\x51\xae\xda\xd4\xd5\x5c\xbd\x92\x12\xd7\xcc\x32\xe3\x56\xa5\x9c\x19\xcf\xf0\x3c\x8b\x07\x56\xe5\x21\x23\x0b\x5c\x09\xbc\x70\x04\xf8\x24\x41\x0d\xcb\xf2\xec\xd1\x4c\xf6\x39\x90\x77\xd5\x6f\x2e\xa9\x35\x9e\xb5\xfc\x31\xee\x74\x6b\x37\x84\xdc\x97\x41\xcd\xcf\x74\xd4\x2c\x7f\xab\xcf\x73\xd4\x7e\x75\xc3\xf8\xee\x41\xf5\x09\x0c\xed\x3d\xb1\x3e\x88\xa1\x35\x1b\xd9\x96\x86\x6f\x76\xe8\xdf\xeb\x30\xc7\x51\xbe\xde\x61\x34\x61\xa4\x30\x30\xf5\xaa\x01\xa3\x67\x63\xb4\xef\x22\xbc\x72\x50\x5b\xf3\x31\x0c\xa9\x61\xab\xb3\xc6\xfa\x8a\x87\x3b\xe5\xa7\x1d\xf3\x7a\x8a\x45\x5d\xef\xae\x0d\x56\xff\x51\x95\xed\x7f\x2f\xa5\x76\x91\x59\x2b\xe5\x45\x6b\xf8\xc9\xb4\xeb\xb2\x68\xed\x58\x44\x3d\x7f\x70\x26\xe4\xea\xfa\x70\x9d\x40\x53\x99\x79\xcb\xb0\xf8\xd0\x59\xfe\xd6\x8c\x6d\x64\xe2\xfa\x67\x98\xcf\x5b\xe0\x0a\x0e\x1b\x89\x07\x90\x23\x70\xd8\x93\x34\xfc\x93\x3a\xcb\x47\xad\x5e\xae\xf4\xa2\xf2\xed\x13\x27\x5f\x7f\x70\xa0\x31\xde\xac\xf9\xa8\x8c\x65\x46\x5f\x35\xab\x64\xf5\xee\x2e\xda\x06\x46\x9e\x59\xfb\x0a\x42\xaf\x4c\xaf\x55\x77\x51\x85\x52\x52\x6d\x64\xbd\x00\xd1\x3b\x59\xf8\x37\x65\x1b\x7b\xa8\x1a\x9f\x9e\x58\x8a\x8c\x5b\x8a\x47\x69\xea\x3f\x56\xf5\xed\xe2\xad\xbe\x77\xca\xdb\x86\x2c\x51\xd5\x25\xdf\xd1\x88\xc9\x3d\x2b\x77\x76\xe2\x91\x1d\xf1\xfa\x2f\xeb\xb4\x5a\x75\x9f\x9e\x30\x18\xbe\x5a\xc1\x7f\xe3\xa9\x7d\x0b\x58\x22\x5d\x29\x66\xab\x0e\x7a\x25\xc9\x67\x41\x75\x40\x1d\xd3\x72\x78\x7e\xab\x02\xbc\x2f\xbd\x1a\x50\x4e\x06\xa6\x70\x87\xc7\x88\x09\xbf\x2a\x8b\xc4\xab\x81\xbc\xc1\xb2\xf0\x5c\x97\x66\x0f\xdc\x75\x74\x6b\xaf\xcc\x8a\xef\xb7\x38\xf1\x1d\x6e\x82\xcf\xfd\x31\xc9\x6a\x89\x6e\xe9\x23\x2c\x10\x9f\x2c\xff\xca\xc6\xdd\x99\xbf\xd4\x8a\x24\xb1\x62\x1d\xc0\x44\x7d\xac\xe4\x8c\xe8\xb3\x52\xbf\xe8\xa2\x65\xba\xeb\xc7\x38\x0d\xe3\xdb\x8f\x7e\x9a\xad\x1d\xa5\x11\xbf\x77\x7a\xf1\xcb\x97\x5f\x46\x17\x1f\x2e\xbd\x9a\x0f\x3b\x54\x2a\x7e\x74\x31\x18\x8e\xc7\xa6\xec\x6b\xbe\xcd\xc7\x24\x02\xbd\xad\x9e\x02\x95\x23\x7b\x86\x76\x0a\x56\x56\x08\x20\x93\xf0\x9e\xea\x2f\x5a\x7c\x20\x65\x4a\xdb\x95\xee\x17\x52\x2a\x8f\x15\x8d\x80\x76\x3d\xd5\x92\x14\x9d\x7c\xeb\x43\x10\xcd\x75\x2c\xee\xba\x50\xd5\xce\x58\x77\xbf\xba\x5d\xe1\x90\x7d\x03\xb8\x3a\xd2\x55\x73\x76\x43\x4e\x62\xa5\x71\x18\xd1\x1b\x5a\xfa\xd7\xd5\x1b\x31\x18\x77\xb6\x6a\xd1\x81\x4e\xae\xf3\xc0\xd4\x2f\xf6\xd8\xdf\xc5\xd1\xed\xbe\xf1\xeb\x7e\x5f\x7c\x7d\x4a\x90\x76\x0c\xbb\x19\xf7\x68\x59\xc1\x01\x14\x20\x17\x1a\x0c\xc3\x00\x9d\x78\x64\x58\xca\xef\x03\x98\x25\xd7\xde\xc4\xbf\xc9\x4c\xef\x8e\x7f\x2a\xc2\xcb\x1e\xe1\xb0\x5d\xa0\x9d\x5b\x96\xda\x88\x0f\x5e\x11\xdd\x0b\x13\xf0\xf8\x6d\xc2\x6e\xad\xcd\xae\xba\x12\xae\x13\x4c\xe1\xda\x7f\x05\x00\x00\xff\xff\xbc\x75\xf6\x19\x7e\x5a\x00\x00") +var _templatesAppTmpl = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xec\x3c\x6b\x73\xe3\x36\x92\x9f\x33\xbf\x02\xc5\x4a\x95\x9c\x44\x96\x1f\xb3\x9b\xdb\x53\x6e\xb6\xca\x23\x6b\x32\xce\x7a\x6c\x9f\xa4\x99\xad\xcb\x8c\x6b\x8a\xa6\x20\x8b\x31\x45\x2a\x04\xe9\xc7\xb8\xf4\xdf\xaf\x1b\x0f\x12\x00\x41\x91\x96\x35\x73\x77\x75\xeb\xdd\x24\x22\xd1\x68\x34\x1a\x8d\x7e\xa1\xc1\xc7\x47\x32\xa5\xb3\x30\xa6\xc4\xf3\x97\x4b\x8f\xac\x56\x2f\x08\x79\x84\x7f\x08\xf1\x8e\xfe\x39\x9e\xd0\xc5\x32\xf2\x33\xfa\x26\x49\x17\x7e\xf6\x81\xa6\x2c\x4c\x62\x8f\xf4\x89\x77\xb8\x7f\xb0\xbf\xbb\xff\xef\xf0\x7f\xaf\x2b\xc0\x07\x49\x3c\x0d\x33\x68\x67\x5e\x5f\xa2\x00\x54\x8f\x24\x93\x38\x88\x77\xe5\x47\x7e\x1c\xd0\x74\x37\x28\x41\x49\x4f\x8c\x59\x01\x5e\xa6\x49\x40\x19\x6b\x05\x9b\xd2\xeb\x90\x65\xe9\x43\x1d\xb0\x77\x91\x86\xb7\x00\x89\x84\x11\xef\x4d\xdc\xef\x0f\xff\xcc\xfd\x08\x09\xfd\x88\x6f\x46\x74\x06\x3f\x0b\x28\xb2\xea\x12\xef\xbf\x28\xe0\xb8\x84\x9f\x0a\xc7\x6b\x20\xfe\x66\x4c\x83\x3c\x0d\xb3\x87\x5f\xd3\x24\x5f\x22\x23\x1e\x75\x74\xf0\xfc\xf1\x91\x63\x43\x16\x99\xb0\x88\xd3\xbb\x14\x14\x49\xa4\xde\x85\x9f\xfa\x0b\x9a\x01\x5b\x39\xaa\xb5\x3c\x5b\x22\x6c\x0b\x7e\x19\x70\x8a\xf6\x41\x94\x33\x18\x46\x5b\x18\x78\x39\x79\x58\x52\x41\x68\x96\x86\xf1\xb5\xd7\x2d\x9b\x8e\xe9\xcc\xcf\xa3\x8c\xb7\x9a\xef\x59\x90\x86\xcb\x4c\x49\x81\x27\x9b\x4a\x2e\x1d\xd3\x65\x94\x3c\x2c\x68\x9c\xbd\xf3\xef\xc3\x45\xbe\x70\x8c\x09\x1d\xcf\xf2\xc5\x15\xd0\xe3\x18\x92\xcb\xd6\x7e\xdd\xa0\xd0\x2a\xf1\x92\x25\x4d\x03\x18\xc6\xbf\xa6\x24\x99\x11\x39\x7d\xca\x48\x96\x90\x1b\x4a\x97\x24\xcd\xe3\x18\xa6\x45\xee\xe6\x61\x44\x41\xca\x91\x2e\x9c\xe6\x3a\x92\xc3\x78\x43\x92\x0f\xd6\x93\x2c\xf0\x6e\x8f\xe4\x61\x7c\x1b\xa6\x49\x8c\x34\xbb\x89\xad\x5f\xd2\x35\x2b\xea\x5c\xd0\x7f\xd0\x87\xaf\x3d\x84\xb6\x3b\xdb\x0d\x63\xe0\x1b\xa4\x14\x37\x40\x18\x83\x80\xc7\x7e\x44\xa2\xc4\x9f\x12\xb5\x6d\x18\xbc\x07\x46\x73\xfc\x84\xe5\x57\x31\xcd\x58\x0d\xc9\x67\x89\xde\x70\x14\x45\xc9\x1d\x9d\x7e\xf0\xa3\x9c\x0a\x3d\xc1\x35\x42\x97\xc3\x91\xcb\xca\x1c\x46\x34\xa2\x3e\x73\xcd\x61\xdb\x3b\x6c\x44\x97\x09\x0b\xb3\x24\x75\xad\xcb\xf3\x06\x1b\x27\x39\x08\x28\x09\x92\x29\x25\x69\x39\x4c\x85\x04\x53\xb3\x6d\x9b\x8a\xc9\x9c\x92\x53\x7d\x11\x09\x93\xe3\x91\x6b\x1c\x90\xcc\x92\x94\x64\xf3\x90\x11\x34\x59\x55\xe2\xe4\x2a\xbb\xc9\x3a\x05\x43\xf1\x1f\x60\xd9\x40\x67\x0f\x0e\xfb\x7d\x01\xdc\xef\x9f\x4c\xff\xbe\x09\xa9\x1f\x2e\x06\x4a\xaa\xda\x51\x55\x2f\xea\x5f\x87\x38\x4b\xf4\x1b\x88\x54\x06\xde\xa0\xce\xda\x6e\x3b\xa3\xe1\x7f\xbe\x3f\x19\x0d\x8f\x7f\x20\xa7\xfe\xe2\x6a\xea\x93\x01\xd8\x96\x64\x31\x49\x96\x61\x40\xde\xfa\xf1\x34\x82\x15\x93\xdb\x81\x28\x8c\x1a\x99\xa0\x0c\x4f\x69\x7c\x9d\xcd\x39\x91\x07\x7a\x93\xb5\xe7\xab\xf4\x5d\x0c\x6a\x38\x57\x32\x0d\x60\x90\x63\x9b\x32\xac\x81\x41\x17\x83\xc1\xc9\xf1\x68\xeb\x22\x8f\x23\x23\x62\xf7\xf0\x86\xcf\xf0\x0e\x5a\x60\x14\x5d\xbe\xbd\x8b\x24\xcd\x2e\xd2\x24\x4b\x82\x24\x32\x69\x9b\x67\xd9\x52\x78\x3d\x28\x5b\x34\xa6\xa9\x06\xe7\xbd\x9d\x4c\x2e\x50\xa5\x9d\xc4\x2c\xc3\x9d\xe6\x6a\xe3\x7b\x9d\xd6\x41\x8c\xbd\x92\x3b\x72\x38\xb6\x7e\xbc\xf1\xb3\x07\x34\x46\xcc\x82\x35\xf3\x9b\x0c\x6a\xa7\x27\x9b\xea\x07\x1b\x8f\x4f\xed\xa1\xa2\x35\x53\x43\xf0\xe7\x0d\x45\x56\xce\xf5\x1e\x51\xc6\xb5\xb2\xb1\xe0\xda\x96\x1b\x25\x51\x8d\xe5\xe4\x7b\xe2\xe4\xe8\x5d\xbf\xcf\x61\xb4\x99\xc0\xe0\xe0\x8a\x64\x21\x35\xb5\x24\x9a\x3d\xc6\xf2\x05\x45\xf8\x8b\x24\x0a\x83\x87\xe3\x24\xc8\x2b\x5e\x86\xd8\x0a\x85\xae\xc0\x58\xe0\x70\x17\xc2\x81\x83\x7f\xd3\x06\xe1\x40\xe3\x0c\x94\x8f\xec\xff\xd1\x68\x22\x16\x3e\x0e\x3e\x9c\xcd\x68\xc0\x8d\x31\x37\xbf\x16\x36\x49\x7a\x18\x07\xe1\xd2\x8f\xc4\x52\x8c\x69\x7a\x1b\x06\x54\x18\xe8\x88\xeb\xa3\x9e\xbf\xf0\xbf\x24\xb1\x7f\xc7\x7a\x41\xb2\x30\x7c\x78\x7d\xa2\x81\x54\x68\xd0\x8f\x65\xac\x5f\x4e\xbc\xb4\xee\xea\x6f\x65\x3c\xeb\xad\x06\x66\x70\xe7\x41\xa9\x01\xf1\x7b\x9e\xf9\x1a\x39\x29\x78\x6d\xf2\xc0\xe6\x80\x80\x7c\x38\x83\x98\x80\xf3\x60\xba\x00\xbf\x11\xe2\x1a\x1f\xac\x70\x85\x17\x5e\xc3\x02\x71\x98\x36\x8b\xc4\x01\x8d\x85\x42\xc6\x56\x96\x42\x63\x99\xf7\x23\x3e\x2a\xc1\x14\x2f\xc8\xaa\x81\x6d\xfa\x53\x09\xb9\xaa\xa8\x58\x4d\xb4\xd7\x88\xb5\x30\x3d\xfd\xfe\x9b\x3c\x16\x54\xb5\x92\xee\x01\x38\x36\x55\x49\x1e\xbf\x7c\x9d\x07\x37\x34\x2b\xa3\xc3\xdf\x92\x50\x8a\xc6\x2e\xcc\x14\xfe\x03\x71\xe5\x6d\x72\x0f\xbf\xcb\x60\x91\x93\x31\x82\xc0\x13\x55\x38\x4c\xbe\x2a\x67\x80\x58\x3a\xcf\x36\x56\x81\x34\x15\x36\x72\xcf\x40\x5b\xc4\xd8\x18\x2f\xee\xcd\x78\xdc\x0d\xcf\xbd\x2f\xe1\xd2\x13\x83\xd4\x8a\x9f\xb4\xbd\x88\x45\xee\x04\x7a\x2f\x7c\x62\x53\x1e\xdf\xd1\x05\x78\x75\xe3\xf0\x0b\x67\xe7\xc1\xe1\xdf\xcc\x66\xa5\x50\x04\xd1\xbf\xd2\xec\x28\x13\x52\x51\xd1\x3a\x28\x13\x69\x5c\xd9\x61\xde\x28\x8f\xb3\x50\xc8\x70\x0c\x1c\xff\x83\x99\x03\x4c\xa0\x2d\xc9\xb9\x6c\xbd\xdc\xf7\xea\x45\xc1\x1d\x07\xa7\x85\x3e\xac\x0d\x85\x03\x08\x8d\xfe\x48\xae\xda\x80\xaa\xa8\xf9\x09\xa0\x4c\xa8\x9c\x36\xe9\x08\x1b\xab\x0b\x58\xf9\xb6\x5e\x0d\x32\x96\x89\x94\x84\x69\x15\xce\xf3\x6c\x99\x67\xcd\x99\x96\x44\xc2\x35\xce\xaa\x11\xb0\x98\x94\x09\x59\x86\x04\x59\x66\xb9\x25\xa8\x7f\x30\x7c\x12\xc2\x24\xe5\xbb\x80\xb3\xcd\xdd\x0b\xfc\x07\x46\xa4\xf1\x94\xe3\xd5\x32\x53\xae\x54\x90\x48\x54\x3d\x92\xd4\x8f\x21\x9a\xfe\xfe\x86\xf4\x5f\x91\xde\x30\x06\x02\x51\x7d\x32\x35\x09\x91\xb5\x01\xb8\x7c\x09\x3a\x01\xe1\x56\xab\xd2\x66\x54\x93\x41\xb8\x35\x3d\x4d\xa2\x21\xd2\xf6\xaf\x22\x3a\x35\x31\x94\x5d\xcf\x12\xbe\x37\x9c\x59\x25\x7c\x33\x86\x3d\x1e\x88\xed\xb3\xaf\x6f\x73\x13\xdf\x1b\xb5\xcd\x85\x26\xc1\xad\xbf\x7b\xc0\xa9\x90\x84\x94\x7c\x59\xcf\x21\x95\xfc\xb1\xb8\x43\x39\x77\x0a\x9e\x94\x83\xd3\x1e\x72\xcb\xa0\x40\xf3\x32\x94\xc6\x1d\x24\x8b\x85\x7f\x4c\xa3\x70\x11\x66\x74\x8a\xde\x8f\xa7\x25\x4f\xca\x1c\x48\x77\xbf\x7b\xf8\xd7\x9f\xf5\x36\x23\x72\x10\x09\x94\x4a\xe6\x23\xcd\xe3\x2e\x19\x5c\xbc\x27\x79\x1c\x66\xe2\x0d\xc5\x3d\x46\xbb\x04\x14\x1a\x79\xf7\x1a\x7b\x8c\x8e\xde\x69\x2d\x5e\xb9\x17\xda\x72\xa6\x90\x5a\xce\x04\xef\x34\xb9\x36\x83\x57\x87\xa8\x16\x30\x42\x38\xbb\x0d\x23\x68\x9b\xbd\x6e\x0c\xd3\x84\x25\xd7\x8c\xff\x5b\x00\xb5\x19\xa2\x54\x3d\x6a\x81\xbf\x5f\xf8\x71\x38\xa3\x2c\xd3\x56\x18\x5e\x87\x33\xd2\x7b\xeb\x43\xb4\xa9\xf8\x2c\x97\xbe\x4e\x24\xdc\x42\x31\x1c\x8c\x27\x3e\xbb\x39\x46\x2a\xc2\xcc\x11\x18\x2e\x81\x56\x76\xce\x8d\x9a\x61\xb7\xbb\x85\x63\xc6\xed\xc4\xa5\x23\xc4\x13\xe0\x18\xb3\xd9\x63\x68\xc0\x9a\xfb\x72\xd0\xdb\x6f\x67\xe3\xe5\xc0\x93\xe4\x86\xc6\x8d\x66\xac\xd6\x84\x49\x1f\xac\xc6\x1f\xb0\xbc\x00\x70\x9e\x82\x1b\xde\x83\x6f\x5d\x5c\x96\x82\x87\x5e\xd5\x33\xd0\x73\x45\x05\x22\xf5\xce\x02\xb5\x12\x7d\x05\xb8\xfe\xde\xea\x52\xf8\x1c\x12\x14\x9f\x2d\x10\xe4\xb8\x54\x53\xba\x8a\xa7\xa8\x3e\x3f\x67\xd0\x28\x94\xfb\x5a\x3f\xcd\x2d\x2f\x9a\x6e\x2d\x17\xab\x38\x19\x10\x94\x5b\x0a\xb5\x64\x55\xb7\x46\xb6\x34\xd2\x85\x6c\x43\x1f\x90\xee\xd7\x2a\x3d\xb4\x32\x3d\x4d\x4f\xdf\x17\x3d\x05\xa5\xdc\x55\x3e\x98\x73\x50\x5d\x99\x68\xd8\x0c\x71\x71\x48\x1a\x17\xf1\xf2\x7d\x83\xb0\x2b\x06\xfd\xaf\x90\x72\xed\x58\xa0\x10\x17\xf5\xce\x02\x05\x5d\x1e\xa6\x74\x3a\x48\xf2\x58\x73\x94\x9b\xcd\x9b\xc3\xc2\x48\x1b\xf7\xcd\xb6\x5b\x55\x87\xad\xa3\xb3\xaa\x90\xec\xdd\x5b\xf8\xc7\x85\x4b\x53\xca\x41\x85\x6b\xd6\xd1\xc2\x85\x38\x01\x30\xfa\x57\xcf\x1f\xea\xb1\x88\xb3\x8f\x06\x2c\xf2\xe0\xc5\xc2\x82\x29\x55\xb5\x19\x1c\xb1\x68\x69\x19\x7a\x98\x4e\x52\x69\x26\x7b\x73\x91\xea\x22\xf5\xad\x45\x7a\xd2\xf6\x73\x2c\xa1\x78\xd1\x03\xad\x91\xf9\x60\xfe\x52\xf7\xb2\xba\x77\x2b\xb1\x85\xe5\x2c\x11\x86\xbd\x5d\xfc\xa9\xa3\x6c\xf2\x2c\x9c\xa7\x99\xa6\xe3\x55\xcc\x5e\x37\xc0\xdf\x17\x69\x6d\xdd\x02\x97\x7d\xdc\xdc\xf7\x14\xaa\x52\x64\x15\x9e\x9e\x34\xf3\x92\x7f\xd8\x1f\xf9\xa7\xa9\x47\x00\xb8\xb7\x4e\x0b\x6a\x0f\x41\x37\xc7\xaf\x1d\x9b\x56\xac\xc5\x73\xa8\x17\x89\xb3\xaf\x48\xbe\x1c\xa0\x96\xfe\x8d\xa4\xc2\xed\x8a\x6f\x53\x22\x36\x99\xaa\xfa\xb9\x51\x06\xdb\xc2\xf5\xb4\x63\xab\x4d\xa8\x1d\xa0\xf1\x9b\x85\x41\xfd\x89\xc9\x36\x0f\xd6\x36\xa1\xf0\x6d\xc2\x5c\x27\xb0\xad\x78\x19\xc6\x53\x7a\xaf\x0d\x36\x82\x70\x27\x59\xb0\x6f\xcc\x63\xd7\xee\x6a\x39\x07\xf3\xc4\xb4\x42\xde\x33\x4e\x53\x37\x54\x42\x8e\x03\x90\x96\x53\xc1\xdc\xfe\xe6\x73\xe1\xa7\x2c\x5d\x75\xfc\xd1\x15\xa7\x12\x5d\x81\x75\x7b\xb3\xb3\x55\xf8\xff\xec\x2a\x6d\xa4\x14\xcd\x28\x7c\x13\xad\x58\xb5\x24\x16\xef\xac\x1d\xb9\x3e\xf8\xb0\xfa\x96\xa9\x0b\x2d\x1b\x60\x3b\xd6\xb8\x30\x86\x37\x23\x5c\x96\xe3\xb3\xb1\xf0\x49\x2f\xcd\x03\x9c\x6f\xa8\xc6\xd7\xc7\x59\x35\xd8\x8d\x48\xa4\x92\x03\x79\x16\x71\x6b\xa3\xc6\xa7\xe3\x53\x41\xc2\xd7\x98\xb0\x26\x6e\x3d\xdd\x51\x96\x7d\xb6\x20\xfa\x76\x7a\x68\x23\xe1\x77\xc8\x5e\x5d\x2d\xc6\x33\x99\x63\xe6\xaa\x44\x39\x82\x31\x92\x56\xbd\xe3\x0c\x52\x3d\x0e\x66\xa6\x00\x2b\xa1\x03\x69\x11\xdf\xed\x5e\x15\xf2\x64\x05\x01\x66\x1d\xca\x49\x7c\x0d\x3c\xb6\x23\x9b\xa6\xed\x27\xa1\xec\x18\x47\xa4\xd0\x2e\xf2\xab\x28\x0c\xaa\x21\x90\x37\x08\xa7\xe9\x09\x72\xdb\xdb\xef\xf1\xff\xed\xed\x57\x4e\xd5\x50\x1e\x22\x46\xd7\xf5\xd6\x8e\x7d\x64\x61\x41\xf5\xac\xd2\x1d\xe5\x00\x96\x93\xa5\x7e\x86\xcc\x2d\x8e\x0d\xf2\x26\x4d\x16\x38\xed\x6d\x6e\xe9\xca\x20\x93\x64\xdb\x43\x18\x23\xac\x9a\x12\x34\xcd\x01\x9f\x9e\x92\xf9\xb0\x0c\x4e\xa6\x36\xeb\x2b\x87\x11\xdd\xda\xed\xe6\xca\x8f\x8b\x2d\x12\xf9\x2c\x0b\x83\x52\x79\x80\x9c\x61\x7a\xb7\xd4\x25\xe5\x96\xd9\xcc\x26\x19\x39\xb1\x16\xba\xa0\x9c\x77\xdd\x1e\x15\x62\x4e\xff\x24\xbd\x71\x30\xa7\x80\xc2\x53\x55\x74\x9e\x95\x04\x13\xed\x72\x6d\x15\xb4\x95\x3d\xd3\x2b\xaf\xc4\x46\x3f\x99\x09\x52\x55\xd5\x53\xb7\x26\x52\xb7\x8a\xa3\x2a\x81\xbe\x0d\x68\x45\xf3\x3a\xbc\x73\xd7\x99\x94\x55\x70\x99\xbd\x4d\xf9\xc2\xb5\x8a\x29\x3f\x63\x3e\x4e\xfd\x10\xcb\x33\xc5\xc1\xbb\xc0\x25\x17\x0f\x1e\xb2\x34\xa7\x5d\xfd\x70\xf3\xe7\x7d\x43\x57\x95\x78\xf4\xa3\x32\xd8\xc6\xd3\x88\x96\x9d\x5e\xfe\xbc\x6f\x75\x4b\x13\xc6\x7e\x4f\x62\xaa\x86\x28\x9b\xde\x52\x3f\xca\xe6\x83\x39\x0d\x6e\xec\xf4\xa0\x68\x7a\x98\xcc\x41\x23\xce\x93\x08\xe9\xf3\x0e\xcd\xc5\x3a\xc1\x95\xbe\xe5\x75\x14\x7f\xb5\xd2\x65\xe9\xb5\xfb\x30\x5c\x24\x7a\x64\x3d\x8b\x63\xb7\xd7\x6c\xf2\x37\x61\xca\x32\x7c\x50\xde\x99\xeb\xb8\x5c\x63\xdc\x4b\xe3\xfd\xfb\x78\xee\x9c\x4c\x99\xc2\xd1\x58\xa2\x2a\x73\x36\xb4\x02\xa6\xd4\x6e\x21\x67\x51\x51\xe6\xd6\xb3\xd8\x9a\x45\xd8\x22\xc6\x7f\x03\x81\xe1\x49\x0c\x44\xca\xcd\xa3\x17\x77\xb9\x93\xac\x1b\x04\x49\xdc\xb4\x56\x0a\x99\x6a\x8a\x65\x74\x2d\xf6\xb5\xed\x09\x71\x16\x51\x7d\x73\xd6\xd4\x54\x6b\xd5\x30\xa8\x80\xdb\x06\x73\xe4\x1e\x71\x55\xe9\x8c\x4f\xb5\x94\x88\x65\xc7\x9e\x9b\x60\x21\xb6\x87\x51\x75\x45\xfe\x25\xbd\xff\x47\xa4\xf7\xff\xb7\xdc\x1a\xcf\x97\xdb\xf6\x20\x6b\xca\xf9\xbe\xb9\x89\x11\x19\xa1\x36\x7b\xd4\xa8\x2a\x14\x1e\x0b\xef\x5c\x0a\x5f\x5d\x27\xe5\xe1\x1a\xe0\x5a\x93\xab\xb0\x32\xcb\xd2\xf0\x2a\xcf\x04\x83\xaa\xe4\x70\x20\x45\x4c\x13\x19\x1c\x58\x05\xe9\x1e\xfa\x3f\x5e\x05\x66\x75\xd9\x20\xd8\x82\x90\x6d\x88\x76\xa5\xc2\xb1\xc2\xfd\x16\x87\x4f\x5f\x41\x24\x4f\x5f\x0f\x92\xe4\x26\xa4\x63\x08\x40\x6e\xc2\x18\xa6\x52\xf8\xa8\x38\x71\x53\x00\xfc\x19\x3f\xd9\xc4\xf3\x1a\x03\x87\x95\xf5\x10\x59\x11\x57\x32\xa4\x2e\x00\x97\xf7\xdf\x0a\x09\xc7\xa7\x17\xdf\x71\x38\xc7\xdd\xb9\xae\x68\x2a\xaf\xcb\x35\xc6\x33\xab\x4a\x17\xab\xbd\xe4\x4d\xb1\x52\x5a\x3c\xd7\x94\xa9\x71\x54\x0d\xea\xe5\x34\xe0\x88\xc7\xbf\x25\x57\x65\x65\x19\xbe\x28\xca\x4f\xeb\xa2\xc2\xda\x3a\xd5\xda\xb4\x89\x82\x54\xcb\xc5\xd9\xe2\x07\x58\x26\xb6\x8b\xbf\x8f\x96\x4b\xc9\x9d\x5d\xa4\x58\xcf\x66\x69\x05\xa0\xfc\x6c\xa1\x37\x97\x2f\x34\x98\x67\x56\x77\xae\xad\xed\xd4\x7c\xf8\x83\x7d\x23\xf4\xa9\x94\xdd\x7a\xbf\x87\xcb\x37\x21\x27\xc5\x8e\x33\xbc\x4f\x31\xc6\x19\xc6\x8e\xf1\x3a\x39\xc4\x74\x0c\x34\x4b\x90\x75\x7e\xb1\xab\xcc\xed\xe7\x5b\x3f\x25\x3c\x15\x4f\x5e\x91\x94\xfe\x99\x87\x29\xdd\xe9\xf0\x17\x9d\x1f\x2a\x9d\x11\xd8\xbf\x33\x40\xe1\x71\x97\x4d\x6f\x6a\x80\x83\x28\xc9\xa7\x45\x61\x2e\xf4\x8b\xe9\x1d\x62\xe8\x0d\xb0\xa1\x28\x73\xd8\x71\xf7\xfe\x33\xa7\xe9\x03\xe3\x09\x7b\x7d\x48\xed\xb5\x63\x58\x17\x22\x71\xbe\x08\x38\x1e\xed\x56\xfc\x57\x91\x43\xeb\x93\x8e\x26\x41\x1d\x1b\x76\xd5\x38\x96\xac\x3d\xeb\xd1\xf8\xb6\x77\x76\x7e\x3c\xfc\x3c\x39\x1d\x7f\x1e\x0d\x7f\x1b\x0e\x26\x9f\xdf\x9f\x1d\xbd\x9f\xbc\x3d\x1f\x9d\xfc\x3e\x3c\x06\x4a\x3a\xfb\xcd\x6b\x43\xef\x97\xa8\x92\x95\x68\x42\xaf\x99\x14\xf8\x1d\x7a\x4b\xe3\xac\x4b\x82\x04\x22\xd3\xfb\xec\x07\xf7\xc4\xa0\x95\x81\x74\xf6\xa2\xe4\x7a\xa7\x83\x57\x91\x86\xe3\x09\x19\x0d\x07\xc3\x93\x0f\xc3\x63\x98\x2c\xf9\x89\xfc\x36\x3e\x3f\xeb\x09\x5e\x86\xb3\x07\x81\xf6\x87\x66\xa6\x72\xec\xc6\xda\xf6\xa6\x3c\x7b\x79\x45\x39\x37\xd9\x8e\x60\x79\x57\xa3\x38\x4d\xbb\x64\xea\x67\x7e\x0d\xb1\xf8\x07\xba\x03\xe1\xd6\x40\xd8\xd3\x42\xe8\x0a\xb5\xea\xc7\x4a\xa4\x37\xd6\x22\x43\xf1\x98\xfa\x6c\x7e\x95\xf8\xe9\xb4\x16\x93\x82\x5c\xfa\x8c\xdd\x25\x2d\x00\xe5\xe1\x0d\x2c\x19\x4e\xb9\x27\x98\xf2\x71\xff\xb2\x27\x8b\x91\x5b\x8c\xa4\xae\x3b\x57\x71\x94\x57\xa1\x5b\x2d\x94\xfa\x83\xb5\xda\x41\xd4\xe1\xab\xfd\x5f\x14\x81\xbd\x88\x5f\x2f\xfb\x7b\xf8\x0b\x09\x7f\xfa\xa9\x81\xf1\xf8\x87\x4b\x24\xfb\x7e\x0c\xd5\x74\xfe\x41\x1f\xc8\x2b\x90\xe9\x63\xc5\xc8\x4e\x0b\x4c\xf8\x57\x70\x1e\x26\x59\xc1\xca\xcd\xf8\x5a\x46\xe1\xdf\x6a\x1d\x40\xa5\xb1\x89\x3f\x9c\x37\x25\xef\x37\x62\x4f\xd9\x1d\xe7\x52\x2c\x96\x62\xd2\x85\x94\xa1\xb6\x3c\x52\x32\x07\x2c\xaa\xc1\xfc\xad\x19\xc5\x05\x9c\x9f\x53\xd4\xea\x54\xfd\x6f\x0e\x0e\x61\xbf\x5c\xea\x6e\x13\x3c\x2a\xbd\x3e\xf9\xcb\x5f\x5e\x36\x43\xfa\xd9\x1c\xf4\xd8\x1e\x04\x10\x6c\x0f\xd5\x19\xd7\x5f\x3d\x78\x84\xdf\x9d\xbd\xa2\x74\x5a\x6b\x93\xef\x78\x7b\x9a\xc7\x9d\xc6\x31\x80\xc3\xf3\x64\x0a\xa3\x5c\x9c\x8f\x27\xcd\xe0\x73\xea\x4f\x61\x7d\xfa\xed\xd6\xb6\x73\x14\x04\x74\x99\x75\x00\x3d\x10\x1d\x61\x90\x06\x5c\xdd\xfb\x83\x25\x2d\x28\xe3\x08\xb0\xf2\x0b\xe6\xb5\x8b\x9e\x94\x8d\xe6\x7e\xf7\xee\xee\x6e\x17\x55\xf4\x6e\x9e\x82\x24\xe3\x5d\xe5\x69\x4b\xbc\xef\x19\x4d\x77\x8f\xae\x01\x35\x62\x05\xd7\x31\xda\xab\x18\x44\xbb\xd3\xaa\x11\xb5\x9f\xf3\x05\x13\x57\x84\xfa\xb8\x2a\x4a\xba\xd7\x0a\xe7\x93\xd4\x1c\x4a\x27\xf8\x0a\x20\x99\xdc\x8d\xe9\xa1\xdf\x40\x59\xb6\x23\x25\x56\x33\x49\xe0\xbd\xb6\xd8\x83\x88\xef\x2a\x99\x3e\xa0\xd1\xae\xda\x6c\x1b\xda\xb0\xb9\x78\x53\x2c\x67\xfd\x4e\x17\x8b\xf1\x7b\x8c\x3f\xa1\x83\x57\x6f\xb2\x9c\x68\xde\x4a\x99\x02\x3c\x96\xbd\x46\xb4\x52\xe2\x1c\x56\xdb\x46\xca\x89\xa0\xd9\x10\x05\x01\x10\xec\x74\xf2\x6c\xf6\x37\x87\x0b\xe5\xea\x07\xec\xea\xa0\x19\xea\x68\xfc\x0b\xe6\x79\x7c\x03\x1c\x14\xec\xf9\xe9\x15\xe1\x2f\xc8\xaa\x3d\x46\x08\x2d\x74\x84\x2d\x35\xa2\xce\x1c\x1c\xba\x79\x3c\xd9\x0b\x7d\xa5\xde\x34\x89\xa9\xc3\xe1\xb4\xc1\x1b\x66\xe1\x68\x5e\x07\x0e\x42\x28\x26\x9c\xa6\x49\xda\x31\xdd\xa2\xa4\xc9\xe1\xb1\xe7\xdc\x19\x62\x27\x14\x07\xd1\xbb\x8d\x34\xf1\xa9\xcf\xfc\x30\xda\x69\xd1\xe7\x89\x93\xe3\xfe\x0a\x28\xf9\x63\x90\x0f\xd8\x25\x9a\x7f\xae\x89\x6a\xc3\x0c\x41\x27\x2c\x16\xe0\xe7\x76\x20\x56\x15\x9a\x5a\xbe\xd8\xf2\x22\xdc\x41\x0c\x4c\x77\x14\xb5\xeb\xd9\x80\xf0\x20\xa1\x6b\x84\xc5\x69\x53\x1d\x54\x81\x06\xd3\x5e\x98\x57\x13\x1d\xc7\xa9\x56\xd1\x84\xcc\x95\x55\xa2\x6a\x7e\xbc\x38\x07\x6b\x29\x83\xdc\x51\x6e\x5c\x6f\xb6\xce\x5c\x91\xa9\xac\xdf\xe7\x40\x8d\x91\xb5\x1e\x51\x9f\x26\xf1\xb5\x0a\xa3\x59\x30\xa7\xd3\xdc\xbc\x21\x3d\x96\xef\x86\xf7\x4b\x2c\x2a\x90\x47\xb5\xea\xec\x13\x5b\xac\x4a\x12\x71\x6a\x56\xc9\x79\xf1\x10\xda\x1d\x6e\xeb\xe9\x83\xba\x02\x7d\x9e\x2a\xb5\x09\x96\x07\x74\xd6\x69\xde\x52\xdc\xa8\x7c\xfc\x84\x1f\x72\xfa\x04\x3f\x3f\x79\x66\xba\xe0\x13\x8c\xf2\x49\x85\x73\x25\x80\xcc\x7d\x15\x00\x52\x44\x4b\x80\x81\x78\xc1\x01\x56\xda\xb1\x9b\x23\xc5\xe2\x58\x3f\x91\x00\xb9\xa0\xe9\x22\x64\xcc\x95\x29\x21\x76\xaa\x44\x83\x75\x2d\x29\x31\xd6\x54\xde\x49\x26\xc5\x9d\xd7\xfe\x09\x98\xe1\x1b\xea\xba\x17\x6c\x64\x56\xc8\x86\x8b\xa2\x5d\x40\xc7\x41\xf9\xb6\x66\xd6\x95\x73\x5d\x8e\x78\x2a\x89\xa3\xa9\x2d\x26\xab\x88\xbb\x36\xf0\xd3\xd3\x58\xce\x6f\x61\x89\x0b\x69\xe2\xb6\xf2\x5b\x9f\x8d\x24\x8c\xbe\x18\x48\xd9\x79\x6a\x24\xb5\xd7\x7d\x2b\xcb\xbc\xfe\x0c\x14\xe7\x6c\x97\xfa\x2c\xe3\xf7\x16\xf5\x13\xf5\x27\xe2\xb8\x03\xb7\x66\xf7\xf0\x19\x38\x68\x2e\x70\x70\x3a\x24\x0a\x14\xd5\xda\xcb\x75\xae\xdb\xba\x25\xbf\xb0\xc5\xf1\xc5\x1d\xc7\xd5\x9e\x91\x06\x26\x37\x83\x51\xe7\x51\xe5\xbe\x84\x72\xde\xff\x71\x6b\xb1\xe7\xdf\xfb\xd1\xae\xda\xd4\xd5\x5c\xbd\x50\x12\xd7\xcc\x32\xeb\x56\xa5\x9a\x99\x38\xe1\x79\x12\x0f\x2a\x95\x87\x9c\x2c\x08\x25\xf0\xc2\x11\xe0\x53\x04\x35\x2c\xcb\x93\x47\xb3\xd9\xe7\x40\xde\xd5\xbf\xb9\xa4\xd7\x78\xd6\xf2\xc7\xba\xd3\x6d\xdc\x10\x72\x5f\x06\xb5\x3f\xd3\x51\xb3\xfc\xad\x3e\xcf\x51\xfb\xd5\x0d\xeb\xbb\x07\xe5\x27\x30\x8c\xf7\xa4\xf2\x41\x0c\xa3\xd9\x3a\x6d\x69\xf8\x66\x87\xf9\xbd\x0e\x7b\x1c\xed\xeb\x1d\x56\x13\x66\x0a\x03\x5b\xaf\x5a\x30\xe6\x69\x8c\xf1\x5d\x84\x17\x0e\x6a\x6b\x3e\x86\xa1\x34\x6c\x69\x6b\x2a\x5f\xf1\x70\x1f\xf9\x19\x66\xde\x3c\x62\xd1\xd7\xbb\x5b\x05\xab\xff\xa8\xca\xf6\xbf\x97\x52\xbb\xc8\xbc\x95\x8a\xa2\x35\xfc\x64\xda\x55\x51\xb4\x76\x2c\xb3\x9e\x3f\x3a\x0f\xe4\xea\xfa\x08\x9d\x40\x53\x75\xf2\xc6\xb0\xf8\xd0\x59\xfe\xd6\x8c\x6d\x64\xe3\xfa\x67\x98\xcd\x5b\xe0\x0a\x0e\x1b\x89\x07\x90\x23\x08\xd8\x93\x34\xfc\x42\x9d\xe5\xa3\x95\x5e\xae\xe3\x45\xed\xdb\x27\x4e\xbe\xfe\xe8\x40\x63\xbd\x59\xf3\x51\x99\x8a\x1b\x7d\xd9\xac\x92\xf5\xbb\xbb\xc2\x37\xd0\xae\x78\xdb\xa7\xce\xc6\x37\x11\x7a\xc5\x61\x5b\x79\x33\x55\xaa\x28\xdd\x63\x36\xcb\x11\xbd\x93\x85\x7f\x5d\xb4\xf1\x87\xb2\xf1\xf1\x91\x1f\x98\x09\xbf\xf1\x28\x4d\xfd\x87\xb2\xda\x5d\xbe\x35\x77\x52\x71\xf7\x90\x1f\x5b\x75\x81\xf4\x88\xef\x02\x3e\x01\x27\x1e\xd5\x11\x2f\x03\xf3\x4e\xab\x55\xf7\xf1\x11\x53\xe3\xab\x15\xfc\x37\x9e\x56\xef\x04\x2b\xa4\x2b\xcd\x89\x35\x41\x2f\x15\xf9\x3c\xc5\x0e\xa8\x63\x5a\x0c\x2f\xee\x58\x40\x2c\x66\xd6\x06\xaa\xc9\xc0\x14\x6e\xd1\xa8\xd8\xf0\xab\xa2\x64\xbc\x1c\xc8\x1b\x2c\x73\xcf\x75\x85\xf6\xc0\x5d\x55\xb7\xf6\x02\xad\xfc\x9a\x8b\x13\xdf\xe1\x26\xf8\xdc\x9f\x96\x2c\x97\xe8\x86\x3e\xc0\x02\x89\xc9\x8a\x6f\x6e\xdc\xbe\xf3\x97\x46\xc9\x24\x0a\x1f\x80\xc9\x6a\x59\xc5\x19\xd9\x67\xa5\x7f\xdf\xc5\x38\xf7\xae\x1f\xe3\x34\x8c\x6f\x3e\xf8\x29\x5b\x3b\x4a\x23\x7e\xef\xf4\xfc\xd7\xcf\xbf\x8e\xce\xdf\x5f\x78\x35\x9f\x79\x28\x15\xfe\xe8\x7c\x30\x1c\x8f\x6d\xd9\x37\x22\x9d\x0f\x49\x04\x5a\x5c\xb7\x09\x65\x58\xfb\x0e\xbd\x16\xac\xb3\x90\x40\x48\xc4\x77\xf0\x57\x16\xdc\x62\x45\x01\xd8\x98\x5b\x3f\xc5\x94\xed\xde\x34\x09\x6e\x68\xda\x63\xf0\x1f\x4f\x01\x7f\x07\x63\x73\xb8\xd5\xaa\x0f\xbf\x8a\xfb\xb0\x7c\x9f\x49\x6c\xaa\xd6\x95\xc3\xd7\x7c\x67\x68\xef\x56\x10\xb1\x57\xfd\x7e\x91\x55\x6a\xbf\x87\xbb\x84\xcf\x16\x77\x51\xcd\xd8\xaa\x76\x53\x51\x60\x2d\xa1\xf9\x4c\x8a\xb3\x7a\x57\x1d\x83\xdc\x70\xca\x5e\x1a\xbc\x6c\xd7\x53\xaf\xb5\x71\xae\x44\x5d\x31\x8e\xbb\xb8\x55\x77\x96\xd6\x5d\x12\x6f\x57\xfd\x54\xbd\xc6\x5c\xfa\x25\xba\x4f\xbe\x21\xd7\xb0\x5c\x3a\x8c\xe8\x35\x2d\x92\x04\xe5\x1b\x39\x98\x88\x18\x6b\xd1\x81\x61\xa9\x0b\x23\xf5\xcf\x0e\x55\x3f\xee\x63\x3a\xaf\xe3\x97\xfd\xbe\xfc\x84\x96\x24\xed\x18\x94\x10\xaa\x96\xa2\x0c\x05\x28\x40\x2e\x34\x78\xb7\x01\x66\x22\x90\x61\xa9\xb8\xd4\x60\xd7\x8d\x7b\x13\xff\x9a\xd9\x21\xaa\xf8\xde\x85\xc7\x1e\xc0\x63\x58\xa0\xb3\x5e\xd4\x0b\xc9\xaf\x76\x11\x33\x94\x94\xf0\xf8\x81\xc5\x6e\x6d\xe0\xa1\x6f\x0c\x97\x19\xd6\xb8\xf6\xdf\x01\x00\x00\xff\xff\x5b\x8d\x64\x68\x43\x5b\x00\x00") func templatesAppTmplBytes() ([]byte, error) { return bindataRead( @@ -90,7 +90,7 @@ func templatesAppTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/app.tmpl", size: 23166, mode: os.FileMode(420), modTime: time.Unix(1467071551, 0)} + info := bindataFileInfo{name: "templates/app.tmpl", size: 23363, mode: os.FileMode(420), modTime: time.Unix(1467255543, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -110,7 +110,7 @@ func templatesServiceMysqlTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/service/mysql.tmpl", size: 3447, mode: os.FileMode(420), modTime: time.Unix(1466027039, 0)} + info := bindataFileInfo{name: "templates/service/mysql.tmpl", size: 3447, mode: os.FileMode(420), modTime: time.Unix(1464623978, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -130,7 +130,7 @@ func templatesServicePostgresTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/service/postgres.tmpl", size: 4173, mode: os.FileMode(420), modTime: time.Unix(1466027039, 0)} + info := bindataFileInfo{name: "templates/service/postgres.tmpl", size: 4173, mode: os.FileMode(420), modTime: time.Unix(1464623978, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -150,7 +150,7 @@ func templatesServiceRedisTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/service/redis.tmpl", size: 3162, mode: os.FileMode(420), modTime: time.Unix(1466027039, 0)} + info := bindataFileInfo{name: "templates/service/redis.tmpl", size: 3162, mode: os.FileMode(420), modTime: time.Unix(1464623978, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -170,7 +170,7 @@ func templatesServiceS3Tmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/service/s3.tmpl", size: 4427, mode: os.FileMode(420), modTime: time.Unix(1463932192, 0)} + info := bindataFileInfo{name: "templates/service/s3.tmpl", size: 4427, mode: os.FileMode(420), modTime: time.Unix(1464102225, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -190,7 +190,7 @@ func templatesServiceSnsTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/service/sns.tmpl", size: 2882, mode: os.FileMode(420), modTime: time.Unix(1463932192, 0)} + info := bindataFileInfo{name: "templates/service/sns.tmpl", size: 2882, mode: os.FileMode(420), modTime: time.Unix(1464102225, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -210,7 +210,7 @@ func templatesServiceSqsTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/service/sqs.tmpl", size: 1343, mode: os.FileMode(420), modTime: time.Unix(1463932192, 0)} + info := bindataFileInfo{name: "templates/service/sqs.tmpl", size: 1343, mode: os.FileMode(420), modTime: time.Unix(1464102225, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -230,7 +230,7 @@ func templatesServiceWebhookTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/service/webhook.tmpl", size: 781, mode: os.FileMode(420), modTime: time.Unix(1460407549, 0)} + info := bindataFileInfo{name: "templates/service/webhook.tmpl", size: 781, mode: os.FileMode(420), modTime: time.Unix(1445799814, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/api/models/templates/app.tmpl b/api/models/templates/app.tmpl index 3a5eba826c..234eb90c2f 100644 --- a/api/models/templates/app.tmpl +++ b/api/models/templates/app.tmpl @@ -605,6 +605,7 @@ {{ end }} {{ define "entry_task" }} +{{ $e := . }} { "Fn::If": [ "Blank{{ upper .Name }}Service", { "Name": "{{ .Name }}", @@ -633,7 +634,11 @@ }, "Volumes": [ {{ range .MountableVolumes }} - "{{ . }}", + {{ if eq .Host "/var/run/docker.sock" }} + "{{.Host}}:{{.Container}}", + {{ else }} + { "Fn::Join": [ "", [ "/volumes/", { "Ref": "AWS::StackName" }, "/{{$e.Name}}{{.Host}}:{{.Container}}" ] ] }, + {{ end }} {{ end }} { "Ref" : "AWS::NoValue" } ], @@ -641,7 +646,6 @@ { "Ref" : "AWS::NoValue" } ], "PortMappings": [ - {{ $e := . }} {{ range .PortMappings }} { "Fn::Join": [ ":", [ { "Ref": "{{ upper $e.Name }}Port{{ .Balancer }}Host" }, diff --git a/api/provider/aws/templates.go b/api/provider/aws/templates.go index 260e3eec63..d57b5b6b98 100644 --- a/api/provider/aws/templates.go +++ b/api/provider/aws/templates.go @@ -83,7 +83,7 @@ func templatesServiceSyslogTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/service/syslog.tmpl", size: 4758, mode: os.FileMode(420), modTime: time.Unix(1465162563, 0)} + info := bindataFileInfo{name: "templates/service/syslog.tmpl", size: 4758, mode: os.FileMode(420), modTime: time.Unix(1463789829, 0)} a := &asset{bytes: bytes, info: info} return a, nil } From 814466582f7cff5bbb05f0e3f2fb17151c1d1060 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 29 Jun 2016 23:07:45 -0400 Subject: [PATCH 10/24] dont export helper struct --- api/models/manifest.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/models/manifest.go b/api/models/manifest.go index 3f479574fc..a3a66e7520 100644 --- a/api/models/manifest.go +++ b/api/models/manifest.go @@ -469,13 +469,13 @@ func (me ManifestEntry) EnvMap() map[string]string { return envs } -type MountableVolume struct { +type mountableVolume struct { Host string Container string } -func (me ManifestEntry) MountableVolumes() []MountableVolume { - volumes := []MountableVolume{} +func (me ManifestEntry) MountableVolumes() []mountableVolume { + volumes := []mountableVolume{} for _, volume := range me.Volumes { parts := strings.Split(volume, ":") @@ -495,7 +495,7 @@ func (me ManifestEntry) MountableVolumes() []MountableVolume { continue } - volumes = append(volumes, MountableVolume{ + volumes = append(volumes, mountableVolume{ Host: parts[0], Container: parts[1], }) From c48ea2191d30295b7cee20645b8cdc88eaa3e109 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 29 Jun 2016 23:09:26 -0400 Subject: [PATCH 11/24] on second thought do export struct just comment it --- api/models/manifest.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/api/models/manifest.go b/api/models/manifest.go index a3a66e7520..f64e5d310c 100644 --- a/api/models/manifest.go +++ b/api/models/manifest.go @@ -469,13 +469,14 @@ func (me ManifestEntry) EnvMap() map[string]string { return envs } -type mountableVolume struct { +// mountable volumes from a given manifest entry +type MountableVolume struct { Host string Container string } -func (me ManifestEntry) MountableVolumes() []mountableVolume { - volumes := []mountableVolume{} +func (me ManifestEntry) MountableVolumes() []MountableVolume { + volumes := []MountableVolume{} for _, volume := range me.Volumes { parts := strings.Split(volume, ":") @@ -495,7 +496,7 @@ func (me ManifestEntry) MountableVolumes() []mountableVolume { continue } - volumes = append(volumes, mountableVolume{ + volumes = append(volumes, MountableVolume{ Host: parts[0], Container: parts[1], }) From c79f59af27650346a6f328ec27c4eb6c1e0c2e94 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 29 Jun 2016 23:22:47 -0400 Subject: [PATCH 12/24] satisfy hound --- api/manifest/manifest.go | 4 ++-- api/models/manifest.go | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/api/manifest/manifest.go b/api/manifest/manifest.go index baeb172b87..3c759c23e7 100644 --- a/api/manifest/manifest.go +++ b/api/manifest/manifest.go @@ -1000,9 +1000,9 @@ func (me ManifestEntry) Label(key string) string { // LabelsByPrefix filters Docker Compose label names by prefixes and returns // a map of label names to values that match. -func (me ManifestEntry) LabelsByPrefix(prefix string) map[string]string { +func (e ManifestEntry) LabelsByPrefix(prefix string) map[string]string { returnLabels := make(map[string]string) - switch labels := me.Labels.(type) { + switch labels := e.Labels.(type) { case map[interface{}]interface{}: for k, v := range labels { ks, ok := k.(string) diff --git a/api/models/manifest.go b/api/models/manifest.go index f64e5d310c..849d8c9a6c 100644 --- a/api/models/manifest.go +++ b/api/models/manifest.go @@ -164,9 +164,10 @@ func (m Manifest) AppName() string { return m[0].app.Name } -func (me ManifestEntry) LabelsByPrefix(prefix string) map[string]string { +// LabelsByPrefix will return the labels that have a given prefix +func (e ManifestEntry) LabelsByPrefix(prefix string) map[string]string { returnLabels := make(map[string]string) - switch labels := me.Labels.(type) { + switch labels := e.Labels.(type) { case map[interface{}]interface{}: for k, v := range labels { ks, ok := k.(string) @@ -469,16 +470,17 @@ func (me ManifestEntry) EnvMap() map[string]string { return envs } -// mountable volumes from a given manifest entry +// MountableVolume describes a mountable volume type MountableVolume struct { Host string Container string } -func (me ManifestEntry) MountableVolumes() []MountableVolume { +// MountableVolumes return the mountable volumes for a manifest entry +func (e ManifestEntry) MountableVolumes() []MountableVolume { volumes := []MountableVolume{} - for _, volume := range me.Volumes { + for _, volume := range e.Volumes { parts := strings.Split(volume, ":") // if only one volume part use it for both sides From 1657d67e144063160178bf96ce511d637a0a3870 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Tue, 12 Jul 2016 11:52:13 -0600 Subject: [PATCH 13/24] keep trying to mount nfs until done --- api/dist/kernel.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/dist/kernel.json b/api/dist/kernel.json index 73e4c4a8d3..6fae85a06e 100644 --- a/api/dist/kernel.json +++ b/api/dist/kernel.json @@ -908,11 +908,11 @@ " - mkdir /volumes\n", { "Fn::If": [ "RegionHasEFS", { "Fn::Join": [ "", [ - " - mount -t nfs -o nfsvers=4.1 $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).", + " - while true; do mount -t nfs -o nfsvers=4.1 $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).", { "Ref": "VolumeFilesystem" }, ".efs.", { "Ref": "AWS::Region" }, - ".amazonaws.com:/ /volumes\n" + ".amazonaws.com:/ /volumes && break; sleep 5; done\n" ] ] }, "" ] }, @@ -1461,7 +1461,7 @@ "Condition": "RegionHasEFS", "Properties": { "FileSystemTags": [ - { "Key": "Name", "Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "volumes" ] ] } } + { "Key": "Name", "Value": { "Fn::Join": [ "-", [ { "Ref": "AWS::StackName" }, "shared-volumes" ] ] } } ] } }, From e2ec74923d85565e6ed36da0ad5ea09bacb22e13 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Fri, 8 Jul 2016 14:16:07 -0400 Subject: [PATCH 14/24] make container disk size configurable --- api/dist/kernel.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/dist/kernel.json b/api/dist/kernel.json index f96f2517fe..3024778a33 100644 --- a/api/dist/kernel.json +++ b/api/dist/kernel.json @@ -156,6 +156,11 @@ "Description": "SSL certificate", "Default": "" }, + "ContainerDisk": { + "Type": "Number", + "Description": "Default container disk size in GB", + "Default": "10" + }, "Development": { "Type": "String", "Description": "Development mode", @@ -903,6 +908,7 @@ " - head -n -1 /etc/sysconfig/docker >> /etc/sysconfig/docker-tmp\n", " - mv /etc/sysconfig/docker-tmp /etc/sysconfig/docker\n", " - echo 'OPTIONS=\"--default-ulimit nofile=1024000:1024000\"' >> /etc/sysconfig/docker\n", + { "Fn::Join": [ "", [ " - echo 'OPTIONS=\"${OPTIONS} --storage-opt dm.basesize=", { "Ref": "ContainerDisk" }, "G\"' >> /etc/sysconfig/docker\n" ] ] }, { "Fn::If": [ "BlankCertificate", { "Fn::Join": [ "", [ " - echo 'ECS_ENGINE_AUTH_DATA={\"index.docker.io\":{\"username\":\"\",\"password\":\"\",\"email\":\"\"},\"", { "Fn::Join": [ ":", [ { "Fn::GetAtt": [ "Balancer", "DNSName" ] }, "5000" ] ] }, "\":{\"username\":\"convox\",\"password\":\"", { "Ref": "Password" }, "\",\"email\":\"user@convox.io\"}}' >> /etc/ecs/ecs.config\n", From 34dba481bdd968ef7458473df02b71915ee57d8e Mon Sep 17 00:00:00 2001 From: David Dollar Date: Fri, 8 Jul 2016 13:21:25 -0400 Subject: [PATCH 15/24] if copying a file, only sync that file --- api/manifest/manifest.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/api/manifest/manifest.go b/api/manifest/manifest.go index a6a02388dc..c5e98efeda 100644 --- a/api/manifest/manifest.go +++ b/api/manifest/manifest.go @@ -1097,6 +1097,17 @@ func (me ManifestEntry) syncAdds(app, process string) error { remote = filepath.Join(wd, remote) } + local := filepath.Join(me.Build, parts[1]) + + info, err := os.Stat(local) + if err != nil { + return err + } + + if !info.IsDir() && strings.HasSuffix(remote, "/") { + remote = filepath.Join(remote, filepath.Base(local)) + } + registerSync(containerName(app, process), filepath.Join(me.Build, parts[1]), remote) } } From 77c995e5899f46aa60b5d43d20d62c35b226df14 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Fri, 8 Jul 2016 15:03:52 -0400 Subject: [PATCH 16/24] display uploading/downloading files when CONVOX_DEBUG is set, fixes #841 --- api/manifest/manifest.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/api/manifest/manifest.go b/api/manifest/manifest.go index c5e98efeda..66291ac813 100644 --- a/api/manifest/manifest.go +++ b/api/manifest/manifest.go @@ -1396,6 +1396,12 @@ func processAdds(prefix string, adds map[string]bool, lock sync.Mutex, syncs []S fmt.Printf(system("%s uploading %d files\n"), prefix, len(adds)) + if os.Getenv("CONVOX_DEBUG") != "" { + for add, _ := range adds { + fmt.Printf(system("%s uploading %s\n"), prefix, add) + } + } + for _, sync := range syncs { var buf bytes.Buffer @@ -1694,6 +1700,12 @@ func (m *Manifest) downloadRemoteAdds(container string, adds map[string]string) fmt.Printf(system("%s downloading %d files\n"), m.systemPrefix(), len(remotes)) + if os.Getenv("CONVOX_DEBUG") != "" { + for _, remote := range remotes { + fmt.Printf(system("%s downloading %s\n"), m.systemPrefix(), remote) + } + } + args := append([]string{"exec", "-i", container, "tar", "czf", "-"}, remotes...) data, err := Execer("docker", args...).Output() From 1189278ba016a2ebcdb9a67e495d4920593d504d Mon Sep 17 00:00:00 2001 From: David Dollar Date: Fri, 8 Jul 2016 15:04:39 -0400 Subject: [PATCH 17/24] satisfy the hound --- api/manifest/manifest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/manifest/manifest.go b/api/manifest/manifest.go index 66291ac813..d8c6c8e0f1 100644 --- a/api/manifest/manifest.go +++ b/api/manifest/manifest.go @@ -1397,7 +1397,7 @@ func processAdds(prefix string, adds map[string]bool, lock sync.Mutex, syncs []S fmt.Printf(system("%s uploading %d files\n"), prefix, len(adds)) if os.Getenv("CONVOX_DEBUG") != "" { - for add, _ := range adds { + for add := range adds { fmt.Printf(system("%s uploading %s\n"), prefix, add) } } From 248511c68df965de19e1cb0ab84da5bca34f4426 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 6 Jul 2016 16:23:48 -0400 Subject: [PATCH 18/24] use aws cli to generate credentials --- cmd/convox/install.go | 97 ++++++++++++++++++++++++++++++++++------- cmd/convox/uninstall.go | 2 +- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/cmd/convox/install.go b/cmd/convox/install.go index 83b39f84fc..ed57b68d13 100644 --- a/cmd/convox/install.go +++ b/cmd/convox/install.go @@ -10,6 +10,7 @@ import ( "math/rand" "net/http" "os" + "os/exec" "regexp" "strings" "time" @@ -34,16 +35,6 @@ type AwsCredentials struct { Expiration time.Time } -var Banner = ` - - ___ ___ ___ __ __ ___ __ _ - / ___\ / __ \ / _ \/\ \/\ \ / __ \/\ \/ \ - /\ \__//\ \_\ \/\ \/\ \ \ \_/ |/\ \_\ \/> -1 { + fmt.Println("Installing the AWS CLI will allow you to install a Rack without specifying credentials.") + fmt.Println("See: http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-set-up.html") + fmt.Println() + return nil, nil + } + + if strings.Index(string(data), "Unable to locate credentials") > -1 { + fmt.Println("You appear to have the AWS CLI installed but have not configured credentials.") + fmt.Println("You can configure credentials by running `aws configure`.") + fmt.Println() + return nil, nil + } + + if strings.Index(string(data), "The user with name convox-install cannot be found") > -1 { + if data, err := awsCLI("iam", "create-user", "--user-name", "convox-install"); err != nil { + return nil, fmt.Errorf(string(data)) + } + + if data, err := awsCLI("iam", "attach-user-policy", "--user-name", "convox-install", "--policy-arn", "arn:aws:iam::aws:policy/AdministratorAccess"); err != nil { + return nil, fmt.Errorf(string(data)) + } + + var ak struct { + AccessKey *AwsCredentials + } + + data, err = awsCLI("iam", "create-access-key", "--user-name", "convox-install") + if err != nil { + return nil, fmt.Errorf(string(data)) + } + + if err = json.Unmarshal(data, &ak); err != nil { + return nil, err + } + + fmt.Println("Successfully created convox-install IAM user. Waiting a few seconds for permissions to stabilize...") + time.Sleep(15 * time.Second) + fmt.Println() + + return ak.AccessKey, nil + } + + return nil, nil +} + +func awsCLI(args ...string) ([]byte, error) { + return exec.Command("aws", args...).CombinedOutput() +} diff --git a/cmd/convox/uninstall.go b/cmd/convox/uninstall.go index f6ba52691b..0139423b64 100644 --- a/cmd/convox/uninstall.go +++ b/cmd/convox/uninstall.go @@ -71,7 +71,7 @@ func cmdUninstall(c *cli.Context) error { credentialsFile = c.Args()[2] } - fmt.Println(Banner) + fmt.Println(banner()) creds, err := readCredentials(credentialsFile) if err != nil { From b75529e72553ffc66fd4ec9c6765c5204c970bac Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 6 Jul 2016 16:25:50 -0400 Subject: [PATCH 19/24] satisfy hound --- cmd/convox/install.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/convox/install.go b/cmd/convox/install.go index ed57b68d13..40fbf5016d 100644 --- a/cmd/convox/install.go +++ b/cmd/convox/install.go @@ -46,7 +46,7 @@ To generate a new set of AWS credentials go to: https://docs.convox.com/creating-an-iam-user` var ( - formationUrl = "https://convox.s3.amazonaws.com/release/%s/formation.json" + formationURL = "https://convox.s3.amazonaws.com/release/%s/formation.json" iamUserURL = "https://docs.convox.com/creating-an-iam-user" isDevelopment = false ) @@ -304,7 +304,7 @@ func cmdInstall(c *cli.Context) error { } versionName := version.Version - formationUrl := fmt.Sprintf(formationUrl, versionName) + furl := fmt.Sprintf(formationURL, versionName) fmt.Printf("Installing Convox (%s)...\n", versionName) @@ -346,7 +346,7 @@ func cmdInstall(c *cli.Context) error { &cloudformation.Parameter{ParameterKey: aws.String("VPCCIDR"), ParameterValue: aws.String(vpcCIDR)}, }, StackName: aws.String(stackName), - TemplateURL: aws.String(formationUrl), + TemplateURL: aws.String(furl), } if tf := os.Getenv("TEMPLATE_FILE"); tf != "" { From e62465d5cbbcad3641ca4da7232a4bb715cdf855 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 6 Jul 2016 16:57:23 -0400 Subject: [PATCH 20/24] read credentials from the cli --- cmd/convox/install.go | 44 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/cmd/convox/install.go b/cmd/convox/install.go index 40fbf5016d..4d0089dc9d 100644 --- a/cmd/convox/install.go +++ b/cmd/convox/install.go @@ -721,7 +721,7 @@ func readCredentials(fileName string) (creds *AwsCredentials, err error) { } if creds.Access == "" || creds.Secret == "" { - creds, err = createCredentialsWithCLI() + creds, err = awsCLICredentials() if err != nil { return nil, err @@ -807,10 +807,10 @@ func readCredentialsFromSTDIN() (creds *AwsCredentials, err error) { return &input.Credentials, err } -func createCredentialsWithCLI() (*AwsCredentials, error) { - data, err := awsCLI("iam", "get-user", "--user-name", "convox-install") +func awsCLICredentials() (*AwsCredentials, error) { + data, err := awsCLI("iam", "get-user") - if strings.Index(err.Error(), "executable file not found") > -1 { + if err != nil && strings.Index(err.Error(), "executable file not found") > -1 { fmt.Println("Installing the AWS CLI will allow you to install a Rack without specifying credentials.") fmt.Println("See: http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-set-up.html") fmt.Println() @@ -824,36 +824,24 @@ func createCredentialsWithCLI() (*AwsCredentials, error) { return nil, nil } - if strings.Index(string(data), "The user with name convox-install cannot be found") > -1 { - if data, err := awsCLI("iam", "create-user", "--user-name", "convox-install"); err != nil { - return nil, fmt.Errorf(string(data)) - } - - if data, err := awsCLI("iam", "attach-user-policy", "--user-name", "convox-install", "--policy-arn", "arn:aws:iam::aws:policy/AdministratorAccess"); err != nil { - return nil, fmt.Errorf(string(data)) - } - - var ak struct { - AccessKey *AwsCredentials - } + access, err := awsCLI("configure", "get", "aws_access_key_id") - data, err = awsCLI("iam", "create-access-key", "--user-name", "convox-install") - if err != nil { - return nil, fmt.Errorf(string(data)) - } + if err != nil { + return nil, err + } - if err = json.Unmarshal(data, &ak); err != nil { - return nil, err - } + secret, err := awsCLI("configure", "get", "aws_secret_access_key") - fmt.Println("Successfully created convox-install IAM user. Waiting a few seconds for permissions to stabilize...") - time.Sleep(15 * time.Second) - fmt.Println() + if err != nil { + return nil, err + } - return ak.AccessKey, nil + creds := &AwsCredentials{ + Access: strings.TrimSpace(string(access)), + Secret: strings.TrimSpace(string(secret)), } - return nil, nil + return creds, nil } func awsCLI(args ...string) ([]byte, error) { From 5eae91c4aa743a38c411fd34c291f72600496567 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 6 Jul 2016 16:57:29 -0400 Subject: [PATCH 21/24] drop the banner completely --- cmd/convox/install.go | 10 ---------- cmd/convox/uninstall.go | 2 -- 2 files changed, 12 deletions(-) diff --git a/cmd/convox/install.go b/cmd/convox/install.go index 4d0089dc9d..3f54381340 100644 --- a/cmd/convox/install.go +++ b/cmd/convox/install.go @@ -54,14 +54,6 @@ var ( // https://docs.aws.amazon.com/general/latest/gr/rande.html#lambda_region var lambdaRegions = map[string]bool{"us-east-1": true, "us-west-2": true, "eu-west-1": true, "ap-northeast-1": false, "ap-southeast-2": true, "test": true} -func banner() string { - b := "" - b += "┌" + strings.Repeat("─", len(Version)+21) + "┐\n" - b += "│ Convox Installer (" + Version + ") │\n" - b += "└" + strings.Repeat("─", len(Version)+21) + "┘\n" - return b -} - func init() { rand.Seed(time.Now().UTC().UnixNano()) @@ -218,8 +210,6 @@ func cmdInstall(c *cli.Context) error { stdcli.Error(fmt.Errorf("instance-count must be greater than 1")) } - fmt.Println(banner()) - distinctId, err := currentId() if err != nil { return stdcli.QOSEventSend("cli-install", distinctId, stdcli.QOSEventProperties{Error: err}) diff --git a/cmd/convox/uninstall.go b/cmd/convox/uninstall.go index 0139423b64..6571ee93c6 100644 --- a/cmd/convox/uninstall.go +++ b/cmd/convox/uninstall.go @@ -71,8 +71,6 @@ func cmdUninstall(c *cli.Context) error { credentialsFile = c.Args()[2] } - fmt.Println(banner()) - creds, err := readCredentials(credentialsFile) if err != nil { return stdcli.QOSEventSend("cli-uninstall", distinctId, stdcli.QOSEventProperties{Error: err}) From d74735d323690bbf06bbdf04ba3a159fa0bbee18 Mon Sep 17 00:00:00 2001 From: David Dollar Date: Wed, 6 Jul 2016 17:08:54 -0400 Subject: [PATCH 22/24] bring back the banner --- cmd/convox/install.go | 12 ++++++++++++ cmd/convox/uninstall.go | 2 ++ 2 files changed, 14 insertions(+) diff --git a/cmd/convox/install.go b/cmd/convox/install.go index 3f54381340..ab5ed3ea75 100644 --- a/cmd/convox/install.go +++ b/cmd/convox/install.go @@ -35,6 +35,16 @@ type AwsCredentials struct { Expiration time.Time } +var Banner = ` + + ___ ___ ___ __ __ ___ __ _ + / ___\ / __ \ / _ \/\ \/\ \ / __ \/\ \/ \ + /\ \__//\ \_\ \/\ \/\ \ \ \_/ |/\ \_\ \/> Date: Wed, 13 Jul 2016 12:57:13 -0600 Subject: [PATCH 23/24] Fix imports --- api/controllers/instances.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/controllers/instances.go b/api/controllers/instances.go index 83b70e9148..1015b78ec4 100644 --- a/api/controllers/instances.go +++ b/api/controllers/instances.go @@ -4,7 +4,8 @@ import ( "net/http" "strconv" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/autoscaling" "github.com/convox/rack/api/httperr" "github.com/convox/rack/api/models" "github.com/convox/rack/api/provider" From a029ff00d79d505e6614c7fc0738fbee9de0a978 Mon Sep 17 00:00:00 2001 From: Noah Zoschke Date: Wed, 13 Jul 2016 13:22:07 -0600 Subject: [PATCH 24/24] move test request/response to use TerminateInstanceInAutoScalingGroup API --- test/aws_cycles.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/aws_cycles.go b/test/aws_cycles.go index 59e9e857db..b10df19756 100644 --- a/test/aws_cycles.go +++ b/test/aws_cycles.go @@ -127,7 +127,7 @@ func DescribeStackCycleWithoutQuery(appName string) awsutil.Cycle { func DeleteInstanceCycle(instance string) awsutil.Cycle { return awsutil.Cycle{ - awsutil.Request{"/", "", `Action=TerminateInstances&InstanceId.1=` + instance + `&Version=2015-10-01`}, + awsutil.Request{"/", "", `Action=TerminateInstanceInAutoScalingGroup&InstanceId=` + instance + `&ShouldDecrementDesiredCapacity=false&Version=2011-01-01`}, awsutil.Response{200, ""}, } }